1

Is that a dynamic way to change ng-include controller?

My app allows users to create page some content and controllers. I can change ng-include src but I don't know how to dynamic associate a new controller. The following code isn't working:

<div ng-app="MyApp">
    <div ng-controller="ParentController">
        <select ng-model="currentItem" ng-options="item as item.url for item in items track by item.url">
        </select>
        {{ currentItem }}
        <div ng-include src="currentItem.url" ng-controller="currentItem.controller"></div>
    </div>
</div>

And I have the following JS:

var app = angular.module("MyApp",[]);

app.controller('ParentController', ['$scope',function($scope){
    $scope.items = [{
        url: 'page1.html',
        controller: 'Page1Controller'
    },
    {
        url: 'page2.html',
        controller: 'Page2Controller'
    }];
    $scope.currentItem = {};
}]);

app.controller('Page1Controller', ['$scope',function(){
    alert('Page1');
}]);

app.controller('Page2Controller', ['$scope',function(){
    alert('Page2');
}]);
1
  • Use directives instead of ng-include, that is what they are meant for. Commented Jun 22, 2015 at 12:53

2 Answers 2

3

I've done by using a directive instead:

<div ng-include src="currentItem.url" dyn-controller="currentItem.controller"></div>

JS Directive:

app.directive('dynController', ['$compile', '$parse',function($compile, $parse) {
  return {
    restrict: 'A',
    terminal: true,
    priority: 100000,
    link: function(scope, elem, attrs) {
            // Parse the scope variable
            var name = $parse(elem.attr('dyn-controller'))(scope);
            elem.removeAttr('dyn-controller');
            elem.attr('ng-controller', name);

            // Compile the element with the ng-controller attribute
            $compile(elem)(scope);       
  };
}]);

The trick here is watching for attribute changes, add ng-controller and then compile the element.

Thanks for

How to watch property in attrs of directive

and

Dynamic NG-Controller Name

Sign up to request clarification or add additional context in comments.

2 Comments

One year later, this is exactly what I need. Let's hope it works :) Thanks
terminal = true is crucial to get it working
0

The following array of items is an array of plain objects that have two fields: url and controller, both containing string values.

 $scope.items = [{
        url: 'page1.html',
        controller: 'Page1Controller'
    },... ]

What you really need is a reference to the function and that can be achieved with the $injector service.

Eventough this might work, I don't get why you aren't using the ParentController to alter the object in your array (or a directive).

2 Comments

I'm not using ParentController because the the array of items and also the controller declaration, is dynamically created by my user.
Must have misinterpret your question. But you did state that this is the code you 'already' have. Nevertheless you're just binding a string instead of a controller function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.