work example ejemplo doesn javascript angularjs angularjs-ng-repeat angularjs-ng-include angularjs-ng-init

javascript - example - ng include ejemplo



Ámbito de paso angular a ng-include (8)

Tengo un controlador que escribí que uso en varios lugares de mi aplicación con ng-include y ng-repeat , así:

<div ng-repeat="item in items" ng-include="''item.html''" ng-controller="ItemController" ></div>

En el controlador / plantilla, espero que exista el valor del item , y todo se basa en esta idea. Ahora, sin embargo, necesito usar el controlador de una manera ligeramente diferente, sin la ng-repeat , pero todavía necesito poder pasar un item . Vi ng-init y pensé que podría hacer lo que necesitaba, así:

<div ng-init="item = leftItem" ng-include="''item.html''" ng-controller="ItemController" ></div> <div ng-init="item = rightItem" ng-include="''item.html''" ng-controller="ItemController" ></div>

Pero eso no parece estar funcionando. ¿Alguien tiene alguna idea de cómo puedo pasar una variable para el alcance en una instancia singular como esta?

Editar: el controlador de arriba está cargando en los valores leftItem y rightItem , algo como esto:

.controller(''MainController'', function($scope, ItemModel) { ItemModel.loadItems() .then(function(items) { $scope.$apply(function() { $scope.leftItem = items.left; $scope.rightItem = items.right; }); }); });


La respuesta de LOVE @ Tanin. resuelve muchos problemas a la vez y de una manera muy elegante. Para aquellos de ustedes como yo que no conocen Coffeescript, aquí está el javascript ...

NOTA: Por razones que soy demasiado nuevo para entender, este código requiere que cite el nombre de su plantilla una vez , en lugar de los requisitos de ng-include para citar dos veces los nombres de su plantilla, es decir. <div ng-include-template="template-name.html" ... > lugar de <div ng-include-template="''template-name.html''" ... >

.directive(''ngIncludeTemplate'', function() { return { templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; }, restrict: ''A'', scope: { ''ngIncludeVariables'': ''&'' }, link: function(scope, elem, attrs) { var vars = scope.ngIncludeVariables(); Object.keys(vars).forEach(function(key) { scope[key] = vars[key]; }); } } })


Más arriba no funcionará para atributos de segundo nivel, como <div ng-include-template=... ng-include-variables="{ id: var.id }"> . Observe la var.id

Directiva actualizada (fea, pero funciona):

.directive(''ngIncludeTemplate'', function() { return { templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; }, restrict: ''A'', scope: { ''ngIncludeVariables'': ''&'' }, link: function(scope, elem, attrs) { var cache = scope.ngIncludeVariables(); Object.keys(cache).forEach(function(key) { scope[key] = cache[key]; }); scope.$watch( function() { var val = scope.ngIncludeVariables(); if (angular.equals(val, cache)) { return cache; } cache = val; return val; }, function(newValue, oldValue) { if (!angular.equals(newValue, oldValue)) { Object.keys(newValue).forEach(function(key) { scope[key] = newValue[key]; }); } } ); } }; });


Puede usar el atributo onload que proporciona ngInclude para hacer esto:

<div ng-include="''item.html''" ng-controller="ItemController" onload="item = rightItem"> </div>

Enlace a la documentación .

EDITAR

Intenta hacer algo como esto en el alcance principal:

$scope.dataHolder = {};

Luego, cuando se reciben los datos asíncronos, almacene los datos en dataHolder :

$scope.dataHolder.leftItem = items.leftItem; $scope.dataHolder.rightItem = items.rightItem;

Ahora cuando ng-include carga la plantilla, creará un ámbito hijo que hereda las propiedades del elemento primario. Entonces $scope.dataHolder se definirá en este ámbito hijo (inicialmente como un objeto vacío). Pero cuando se reciben sus datos asincrónicos, la referencia al objeto vacío debe contener los datos recién recibidos.


Tal vez una actualización obvia para las respuestas de Mike y Tanin, si usas plantillas en línea como:

<script type="text/ng-template" id="partial">{{variable}}</script> <div ng-include-template="''partial''" ng-include-variables="{variable: variable}"></div>

Luego, en la directiva ngIncludeTemplate, reemplace

templateUrl: function(elem, attrs) { return attrs.ngIncludeTemplate; },

Con

template: function(elem, attrs) { return document.getElementById(attrs.ngIncludeTemplate.split("''")[1]).innerHTML },


Tarde a la fiesta, pero hay un pequeño "truco" angular para lograr esto sin implementar una directiva tonta.

Agregar una directiva incorporada que amplíe el alcance de su controlador (como ng-if) en todas partes donde use ng-include realmente le permitirá aislar el nombre de la variable para todos los ámbitos incluidos.

Asi que:

<div ng-include="''item.html''" ng-if="true" onload="item = rightItem"> </div> <div ng-include="''item.html''" ng-if="true" onload="item = leftItem"> </div>

A continuación, puede vincular su plantilla item.html a la variable del elemento varias veces con diferentes elementos.

Aquí hay un plunker para lograr lo que quieres

El problema fue que el ítem cambia constantemente en el alcance del controlador que solo contiene una referencia a la variable del ítem que se borra en cada instrucción de carga.

Al presentar una directiva que amplía el alcance actual, le permite tener un alcance aislado para todos los ng-include. Como consecuencia, la referencia del elemento se conserva y es única en todo el alcance extendido.


Terminé reescribiéndolo en una directiva y vinculando el valor necesario en el alcance con

scope: { item: ''='' }


ng-init es mejor para esto, creo.

<div ng-include=''myFile.html'' ng-init="myObject = myCtrl.myObject; myOtherObject=myCtrl.myOtherObject"/>


Usar onload no es una solución limpia porque ensucia el alcance global. Si tienes algo más complejo, comenzará a fallar.

ng-include no es reutilizable porque tiene acceso al alcance global. Es un poco raro.

Lo anterior no es verdad. ng-si con onload no ensucia el alcance global

Tampoco queremos escribir una directiva específica para cada situación.

Hacer una directiva genérica en lugar de ng-include es una solución más limpia.

El uso ideal se ve así:

<div ng-include-template="''item.html''" ng-include-variables="{ item: ''whatever'' }"></div> <div ng-include-template="''item.html''" ng-include-variables="{ item: variableWorksToo }"></div>

La directiva es:

.directive( ''ngIncludeTemplate'' () -> { templateUrl: (elem, attrs) -> attrs.ngIncludeTemplate restrict: ''A'' scope: { ''ngIncludeVariables'': ''&'' } link: (scope, elem, attrs) -> vars = scope.ngIncludeVariables() for key, value of vars scope[key] = value } )

Puede ver que la directiva no usa el alcance global. En su lugar, lee el objeto de ng-include-variables y agrega esos miembros a su propio alcance local.

Espero que esto sea lo que quisieras; es limpio y genérico