javascript - template - ng-controller что это




AngularJS: динамически назначает контроллер из ng-repeat (4)

Ваша проблема в том, что ng-controller должен указывать на сам контроллер, а не только на строку с именем контроллера.

Таким образом, вы можете определить $ scope.sidepanels как массив с указателями на контроллеры, что-то вроде этого, может быть:

$scope.sidepanels = [Alerts, Subscriptions];

Вот рабочий пример на js скрипке http://jsfiddle.net/ADukg/1559/

Тем не менее, я нахожу очень странным всю эту ситуацию, когда вы можете настроить контроллеры в ngRepeat.

Я пытаюсь динамически назначить контроллер для включенного шаблона следующим образом:

<section ng-repeat="panel in panels">
    <div ng-include="'path/to/file.html'" ng-controller="{{panel}}"></div>
</section>

Но Angular жалуется, что {{panel}} не определена.

Я предполагаю, что {{panel}} еще не определен (потому что я могу повторить {{panel}} внутри шаблона).

Я видел много примеров того, как люди устанавливают ng-controller равным такой переменной: ng-controller="template.ctrlr" . Но, не создавая повторяющийся контур совпадения, я не могу понять, как получить значение {{panel}} когда ему нужен ng-controller .

PS Я также попытался установить ng-controller="{{panel}}" в моем шаблоне (думая, что он должен быть разрешен к тому времени), но без кубиков.


Другой способ - не использовать ng-repeat, а директиву для их компиляции.

HTML

<mysections></mysections>

директива

angular.module('app.directives', [])
    .directive('mysections', ['$compile', function(compile){
        return {
            restrict: 'E',
            link: function(scope, element, attrs) {
                for(var i=0; i<panels.length; i++) {
                    var template = '<section><div ng-include="path/to/file.html" ng-controller="'+panels[i]+'"></div></section>';
                    var cTemplate = compile(template)(scope);

                    element.append(cTemplate);
                }
            }
        }
    }]);

Чтобы динамически установить контроллер в шаблон, он помогает ссылаться на функцию конструктора, связанную с контроллером. Функция-конструктор для контроллера - это функция, которую вы передаете методу controller() API модуля Angular.

Это помогает, потому что если строка, переданная директиве ngController не является именем зарегистрированного контроллера, тогда ngController обрабатывает строку как выражение, которое будет оцениваться в текущей области. Это выражение области видимости должно оцениваться конструктором контроллера.

Например, скажем, угловое встречается в шаблоне следующее:

ng-controller="myController"

Если контроллер с именем myController не зарегистрирован, тогда Angular будет смотреть на $scope.myController в текущем контроллере. Если этот ключ существует в области, и соответствующее значение является конструктором контроллера, тогда будет использоваться контроллер.

Это упоминается в документации ngController в описании значения параметра: «Имя глобальной доступной функции конструктора или выражение, которое в текущей области оценивается функцией-конструктором». Комментарии кодов в Угловом исходном коде более подробно описываются здесь в src/ng/controller.js .

По умолчанию Угловой не упрощает доступ к конструктору, связанному с контроллером. Это связано с тем, что, когда вы регистрируете контроллер, используя метод controller() API модуля Angular, он скрывает конструктор, который вы передаете ему в частной переменной. Вы можете увидеть это здесь в исходном коде $ ControllerProvider . ( controllers переменная в этом коде является переменной private для $ControllerProvider .)

Мое решение этой проблемы - создать универсальный вспомогательный сервис под названием registerController для регистрации контроллеров. Эта услуга предоставляет доступ к контроллеру и контроллеру при регистрации контроллера. Это позволяет использовать контроллер как в обычном режиме, так и в динамическом режиме.

Вот код, который я написал для службы registerController которая делает следующее:

var appServices = angular.module('app.services', []);

// Define a registerController service that creates a new controller
// in the usual way.  In addition, the service registers the
// controller's constructor as a service.  This allows the controller
// to be set dynamically within a template.
appServices.config(['$controllerProvider', '$injector', '$provide',
  function ($controllerProvider, $injector, $provide) {
    $provide.factory('registerController',
      function registerControllerFactory() {
        // Params:
        //   constructor: controller constructor function, optionally
        //     in the annotated array form.
        return function registerController(name, constructor) {
            // Register the controller constructor as a service.
            $provide.factory(name + 'Factory', function () {
                return constructor;
            });
            // Register the controller itself.
            $controllerProvider.register(name, constructor);
        };
    });
}]);

Ниже приведен пример использования службы для регистрации контроллера:

appServices.run(['registerController',
  function (registerController) {

    registerController('testCtrl', ['$scope',
      function testCtrl($scope) {
        $scope.foo = 'bar';
    }]);

}]);

Приведенный выше код регистрирует контроллер под именем testCtrl , а также предоставляет конструктор контроллера как службу под названием testCtrlFactory .

Теперь вы можете использовать контроллер в шаблоне либо обычным способом -

ng-controller="testCtrl"

или динамически -

ng-controller="templateController"

Для того, чтобы последние работали, в вашей текущей области вы должны иметь следующее:

$scope.templateController = testCtrlFactory

Я считаю, что у вас есть эта проблема, потому что вы определяете свои контроллеры как это (как и раньше):

app.controller('ControllerX', function() {
    // your controller implementation        
});

Если это так, вы не можете просто использовать ссылки на ControllerX потому что реализация контроллера (или «класс», если вы хотите его назвать) не входит в глобальную область (вместо этого она хранится в приложении $controllerProvider ).

Я предлагаю вам использовать шаблоны вместо динамического назначения контрольных ссылок (или даже вручную их создания).

Контроллеры

var app = angular.module('app', []);    
app.controller('Ctrl', function($scope, $controller) {
    $scope.panels = [{template: 'panel1.html'}, {template: 'panel2.html'}];        
});

app.controller("Panel1Ctrl", function($scope) {
    $scope.id = 1;
});
app.controller("Panel2Ctrl", function($scope) {
    $scope.id = 2;
});

Шаблоны (mocks)

<!-- panel1.html -->
<script type="text/ng-template" id="panel1.html">
  <div ng-controller="Panel1Ctrl">
    Content of panel {{id}}
  </div>
</script>

<!-- panel2.html -->
<script type="text/ng-template" id="panel2.html">
  <div ng-controller="Panel2Ctrl">
    Content of panel {{id}}
  </div>
</script>

Посмотреть

<div ng-controller="Ctrl">
    <div ng-repeat="panel in panels">
        <div ng-include src="panel.template"></div>        
    </div>
</div>

jsFiddle: http://jsfiddle.net/Xn4H8/





assign