descargar - angularjs vs angular
Cómo "quitar" una expresión (5)
Digamos que tengo una repetición ng con una gran matriz.
Cuando se ejecuta ng-repeat, agrega todos los elementos de esa matriz a un alcance aislado, además de tener la matriz en un alcance. Eso significa que $ digest comprueba toda la matriz para ver los cambios, y además de eso, verifica cada elemento individual en esa matriz para ver los cambios.
Vea este plunker como un ejemplo de lo que estoy hablando.
En mi caso de uso, nunca cambio un solo elemento de mi matriz, así que no es necesario que los vigile. Solo cambiaré la matriz completa, en cuyo caso ng-repeat volvería a representar la tabla en su totalidad. (Si me equivoco sobre esto, por favor avíseme ...)
En una matriz de (digamos) 1000 filas, son 1000 expresiones más que no necesito evaluar.
¿Cómo puedo eliminar el registro de cada elemento del observador mientras sigo viendo la matriz principal?
Tal vez en lugar de anular el registro, ¿podría tener más control sobre mi $ digest y, de alguna manera, saltear cada fila individual?
Este caso específico es en realidad un ejemplo de un problema más general. Sé que $ watch devuelve una función de ''desreglamentación'' , pero eso no ayuda cuando una directiva registra los relojes, que es la mayor parte del tiempo.
$ watch devuelve una función que desvincula el $ watch cuando se le llama. Así que esto es todo lo que necesita para "watchOnce":
var unwatchValue = scope.$watch(''value'', function(newValue, oldValue) {
// Do your thing
unwatchValue();
});
Editar: vea la otra respuesta que publiqué.
He ido e implementado la idea de Blesh de una manera seperable. Mi directiva ngOnce
simplemente destruye el alcance del niño que crea ngRepeat
en cada artículo. Esto significa que el alcance no se alcanza desde el alcance de sus padres scope.$digest
y los vigilantes nunca se ejecutan.
La directiva en sí:
angular.module(''transclude'', [])
.directive(''ngOnce'', [''$timeout'', function($timeout){
return {
restrict: ''EA'',
priority: 500,
transclude: true,
template: ''<div ng-transclude></div>'',
compile: function (tElement, tAttrs, transclude) {
return function postLink(scope, iElement, iAttrs, controller) {
$timeout(scope.$destroy.bind(scope), 0);
}
}
};
}]);
Utilizándolo:
<li ng-repeat="item in contents" ng-once>
{{item.title}}: {{item.text}}
</li>
Nota ng-once
no crea su propio ámbito, lo que significa que puede afectar a los elementos hermanos. Todos estos hacen lo mismo:
<li ng-repeat="item in contents" ng-once>
{{item.title}}: {{item.text}}
</li>
<li ng-repeat="item in contents">
<ng-once>
{{item.title}}: {{item.text}}
</ng-once>
</li>
<li ng-repeat="item in contents">
{{item.title}}: {{item.text}} <ng-once></ng-once>
</li>
Tenga en cuenta que esta puede ser una mala idea
Puede agregar la directiva bindonce
a su ng-repeat
. Tendrá que descargarlo de https://github.com/pasvaz/bindonce .
editar : algunas advertencias:
Si está utilizando {{}}
interpolación en su plantilla, debe reemplazarla por <span bo-text>
.
Si está utilizando directivas ng-
, debe reemplazarlas por las directivas bo-
right.
Además, si está colocando bindonce
y ng-repeat
en el mismo elemento, intente mover el bindonce
a un elemento primario (consulte https://github.com/Pasvaz/bindonce/issues/25#issuecomment-25457970 ). o agregando track by
su ng-repeat
.
Si está usando angularjs 1.3
o superior, puede usar la sintaxis de enlace único como
<li ng-repeat="item in ::contents">{{item}}</li>
Esto vinculará el valor y eliminará los vigilantes una vez que se ejecuta el primer ciclo de resumen y el valor cambia de undefined
a defined
por primera vez.
Un BLOG muy útil sobre esto.
Tener un repetidor con una gran matriz que no mires para ver cada elemento.
Necesitarás crear una directiva personalizada que tome un argumento y una expresión para tu matriz, luego en la función de vinculación solo observarías esa matriz, y tendrías la función de vinculación programáticamente refrescando el HTML (en lugar de usar un ng-repeat)
algo así como (código psuedo):
app.directive(''leanRepeat'', function() {
return {
restrict: ''E'',
scope: {
''data'' : ''=''
},
link: function(scope, elem, attr) {
scope.$watch(''data'', function(value) {
elem.empty(); //assuming jquery here.
angular.forEach(scope.data, function(d) {
//write it however you''re going to write it out here.
elem.append(''<div>'' + d + ''</div>'');
});
});
}
};
});
... que parece un dolor en el trasero.
Método alterno de hackish
Es posible que pueda recorrer $scope.$$watchers
y examinar $scope.$$watchers[0].exp.exp
para ver si coincide con la expresión que desea eliminar y luego eliminarla con un simple splice()
llamada. El PITA aquí, es que cosas como Blah {{whatever}} Blah
between tags serán la expresión, e incluso incluirán retornos de carro.
Por el lado positivo, es posible que puedas recorrer el $ scope de tu ng-repeat y simplemente eliminar todo, luego agregar explícitamente el reloj que quieras ... No sé.
De cualquier manera, parece un truco.
Para eliminar un observador realizado por $ scope. $ Watch
Puede anular el registro de un $watch
con la función devuelta por la llamada $watch
:
Por ejemplo, tener un $watch
only fire una vez:
var unregister = $scope.$watch(''whatever'', function(){
alert(''once!'');
unregister();
});
Por supuesto, puede llamar a la función de cancelar el registro cuando lo desee ... eso fue solo un ejemplo.
Conclusión: no hay realmente una gran manera de hacer exactamente lo que estás preguntando
Pero una cosa a considerar: ¿vale la pena preocuparse? Además, ¿es realmente una buena idea tener miles de registros cargados en docenas de DAMElements cada uno? Comida para el pensamiento.
Espero que eso ayude.
EDIT 2 (se eliminó la mala idea)