Dynamically assign ng controller at runtime

I have a situation where I need to dynamically change the controller so that the scope variables are affected accordingly. General structure:

<div ng-controller="GameController"> // some general HTML which fits all types of games <div ng-controller="someScopeVar"> // Type of game // some game-type-specific ng-models that should respond to the change of controller, ie scope </div </div> 

I saw here that this can be done in ng-repeat . Can this be done outside of this? In other words, can I tell angular to read it as a variable, not a string literal?

+7
javascript angularjs
source share
2 answers

As discussed in the comments, angular has a really powerful function / library for handling these scripts - ui-router (with its powerful wiki ).

ui-router is the answer to the need to create functional elements - states , rather than thinking in view / url (link to the home page):

AngularUI Router is a routing framework for AngularJS that allows you to organize parts of your interface into a state machine . Unlike the $ route service in the Angular ngRoute module, which is organized around URL routes, the ui-router organized around states , which may have optional routes, as well as other attached behavior.

There are some very interesting blog posts:

... The most interesting thing in the new AngularJS router is not the router itself, but the state manager who comes with it. Instead of targeting a controller / view to render for a given URL, you are targeting state. States are managed in a hierarchical hierarchy that ensures the inheritance of parent states and the complex composition of page components, all of which remain declarative in nature ...

... ui-router fully covers the state machine routing system. It allows you to determine the state and transition of your application to these states. The real victory is that it allows you to unleash nested states and make some very complex layouts in an elegant way.

Exactly what we need is to separate child states ... dynamically change the controller actually ... maybe by changing the URL or just changing the state (change one child child instead of another without a URL)

You need to think about your routing a little differently, but as soon as you go around the state approach, I think you'll like it ...

Finally, there are a few links that I would designate as the holy grail of ui-router

  • Sample application . In action, we see how the ui-router state machine works. We can load the list as a parent state , then we can select line items that are our own child state ... while the parent is not reloading ( here I tried to explain this in more detail)

  • state.js is a necessary piece of code for an example application. This is one of the best documented code snippets I've seen ... It took some time to go by and it will give you 80% percent of the answers: how ui-router works

In my experience, this is really suitable for small applications, as well as for large-scale systems ... love it ...

+3
source share

The way this works for ngRepeat is different. It works because it compiles each repetition of what you need to do here.

For example:

 mainCtrl = function($scope, $compile, $element) { $scope.someScopeVar = ctrl1; $scope.changeCtrl = function(id) { $scope.someScopeVar = id === 1 ? ctrl1 : ctrl2; var elm = $element.find('div'); elm.replaceWith($compile(template)($scope)); } } var ctrl1 = function($scope) { $scope.name = 'World'; } var ctrl2 = function($scope) { $scope.name = 'John'; } 

We assign each controller function $scope.someScopeVar , then we must compile the new element with the new controller and replace the old one.

I do not believe that angular has the ability to update the controller on the fly. May be a good idea for a new feature.

Fiddle


Another option is to use the mixin template to update the main area. You will not get a new shiny area, but it may work for your purposes.

 mainCtrl = function($scope, $compile, $element) { angular.extend($scope, ctrl1()); $scope.changeCtrl = function(id) { angular.extend($scope, id === 1 ? ctrl1() : ctrl2()); } } var ctrl1 = function() { var obj = {}; obj.name = 'World'; return obj; } var ctrl2 = function() { var obj = {}; obj.name = 'John'; return obj; } 

Fiddle

+2
source share

All Articles