operator for example javascript dynamic controller angularjs assign

javascript - for - AngularJS: asigna dinĂ¡micamente el controlador desde ng-repeat



ng-repeat example (5)

Intento asignar dinámicamente un controlador para la plantilla incluida de la siguiente manera:

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

Pero Angular se queja de que {{panel}} no está definido.

Supongo que {{panel}} aún no está definido (porque puedo hacer un eco de {{panel}} dentro de la plantilla).

He visto muchos ejemplos de personas configurando ng-controller igual a una variable como la siguiente: ng-controller="template.ctrlr" . Pero, sin crear un bucle concurrente duplicado, no puedo encontrar la manera de tener el valor de {{panel}} disponible cuando ng-controller necesita.

PD: También intenté configurar ng-controller="{{panel}}" en mi plantilla (pensando que ya debía haberlo resuelto), pero no dados.


Creo que estás teniendo este problema porque estás definiendo tus controladores de esta manera (como solía hacer):

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

Si ese es el caso, no puede simplemente usar referencias a ControllerX porque la implementación del controlador (o ''Class'', si quiere llamarlo así) no está en el alcance global (en cambio, se almacena en la aplicación $controllerProvider ).

Le sugiero que use plantillas en lugar de asignar dinámicamente referencias de controlador (o incluso crearlas manualmente).

Controladores

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; });

Plantillas (burlas)

<!-- 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>

Ver

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

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


Ok, creo que la solución más simple aquí es definir el controlador explícitamente en la plantilla de tu archivo. Digamos que tienes una matriz:

$scope.widgets = [ {templateUrl: ''templates/widgets/aWidget.html''}, {templateUrl: ''templates/widgets/bWidget.html''}, ];

Luego en tu archivo html:

<div ng-repeat="widget in widgets"> <div ng-include="widget.templateUrl"></div> </div>

Y la solución aWidget.html:

<div ng-controller="aWidgetCtrl"> aWidget </div>

bWidget.html:

<div ng-controller="bWidgetCtrl"> bWidget </div>

¡Simple como eso! Usted simplemente define el nombre del controlador en su plantilla. Ya que define los controladores como bmleite dijo:

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

entonces esta es la mejor solución que pude encontrar. El único problema aquí es si tienes como 50 controladores, tendrás que definirlos explícitamente en cada plantilla, pero supongo que tienes que hacer esto de todos modos ya que tienes una repetición ng con el controlador establecido a mano.


Otra forma es no usar ng-repeat, sino una directiva para compilarlos en existencia.

HTML

<mysections></mysections>

Directiva

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); } } } }]);


Para establecer dinámicamente un controlador en una plantilla, ayuda tener una referencia a la función constructora asociada a un controlador. La función constructora de un controlador es la función que se transfiere al método controller() de la API del módulo de Angular.

Tener esto ayuda porque si la cadena que pasa a la directiva ngController no es el nombre de un controlador registrado, entonces ngController trata la cadena como una expresión para ser evaluada en el alcance actual. Esta expresión de ámbito debe evaluar a un constructor de controlador.

Por ejemplo, supongamos que Angular encuentra lo siguiente en una plantilla:

ng-controller="myController"

Si no se registra ningún controlador con el nombre myController , Angular mirará $scope.myController en el controlador actual que contiene. Si esta clave existe en el alcance y el valor correspondiente es un constructor de controlador, entonces se usará el controlador.

Esto se menciona en la documentación de ngController en su descripción del valor del parámetro: "Nombre de una función de constructor accesible globalmente o una expresión que en el ámbito actual se evalúa como una función de constructor". Los comentarios de código en el código fuente angular deletrean esto con más detalle aquí en src/ng/controller.js .

Por defecto, Angular no facilita el acceso al constructor asociado a un controlador. Esto se debe a que cuando registra un controlador utilizando el método controller() de la API del módulo de Angular, oculta el constructor en el que lo pasa en una variable privada. Puede ver esto aquí en el código fuente $ ControllerProvider . (La variable de controllers en este código es una variable privada a $ControllerProvider ).

Mi solución a este problema es crear un servicio auxiliar genérico llamado registerController para registrar controladores. Este servicio expone tanto el controlador como el constructor del controlador al registrar un controlador. Esto permite que el controlador se use tanto de forma normal como dinámica.

Aquí está el código que escribí para un servicio registerController que hace esto:

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); }; }); }]);

Aquí hay un ejemplo de cómo usar el servicio para registrar un controlador:

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

El código anterior registra el controlador bajo el nombre testCtrl , y también expone el constructor del controlador como un servicio llamado testCtrlFactory .

Ahora puede usar el controlador en una plantilla, ya sea de la manera habitual--

ng-controller="testCtrl"

o dinámicamente--

ng-controller="templateController"

Para que esto último funcione, debe tener lo siguiente en su alcance actual:

$scope.templateController = testCtrlFactory


Su problema es que ng-controller debe apuntar al controlador en sí, no solo a la cadena con el nombre del controlador.

Así que es posible que desee definir $ scope.sidepanels como una matriz con punteros a los controladores, algo como esto, tal vez:

$scope.sidepanels = [Alerts, Subscriptions];

Aquí está el ejemplo de trabajo en js fiddle http://jsfiddle.net/ADukg/1559/

Sin embargo, me parece muy extraña toda esta situación cuando es posible que desee configurar controladores en ngRepeat.