Lo que estoy tratando de implementar es básicamente un controlador "en repetición finalizada de renderizado". Puedo detectar cuándo está hecho, pero no puedo entender cómo activar una función a partir de él.
Verifique el violín: http://jsfiddle.net/paulocoelho/BsMqq/3/
JS
var module = angular.module('testApp', [])
.directive('onFinishRender', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
element.ready(function () {
console.log("calling:"+attr.onFinishRender);
// CALL TEST HERE!
});
}
}
}
});
function myC($scope) {
$scope.ta = [1, 2, 3, 4, 5, 6];
function test() {
console.log("test executed");
}
}
HTML
<div ng-app="testApp" ng-controller="myC">
<p ng-repeat="t in ta" on-finish-render="test()">{{t}}</p>
</div>
Respuesta : violín de trabajo desde el acabadomove: http://jsfiddle.net/paulocoelho/BsMqq/4/
element.ready()
fragmento? Quiero decir ... ¿es algún tipo de complemento jQuery que tienes, o debería activarse cuando el elemento está listo?Respuestas:
Tenga en cuenta que no lo usé,
.ready()
sino que lo envolví en un$timeout
.$timeout
se asegura de que se ejecute cuando los elementos ng repetidos hayan REALIZADO REALMENTE la representación (porque$timeout
se ejecutará al final del ciclo de resumen actual, y también llamará$apply
internamente, a diferenciasetTimeout
). Entonces, una vezng-repeat
finalizado, usamos$emit
para emitir un evento a ámbitos externos (ámbitos primarios y primarios).Y luego en su controlador, puede atraparlo con
$on
:Con html que se parece a esto:
fuente
$timeout
(que es básicamentesetTimeout
+ Angular$scope.$apply()
) consetInterval
.$timeout
se ejecutará solo una vez por laif
condición, y eso será al comienzo del próximo$digest
ciclo. Para obtener más información sobre los tiempos de espera de JavaScript, consulte: ejohn.org/blog/how-javascript-timers-worksetTimeout()
con 0 de retraso es otra pregunta, aunque debo decir que nunca he encontrado una especificación real para la cola de eventos del navegador en ningún lado, solo lo que está implicado por un solo subproceso y la existencia desetTimeout()
.on-finish-render="ngRepeatFinished"
? Cuando asignoon-finish-render="helloworld"
, funciona igual.Use $ evalAsync si desea que su devolución de llamada (es decir, test ()) se ejecute después de que se construya el DOM, pero antes de que se muestre el navegador. Esto evitará el parpadeo - ref .
Violín .
Si realmente desea llamar a su devolución de llamada después de renderizar, use $ timeout:
Prefiero $ eval en lugar de un evento. Con un evento, necesitamos saber el nombre del evento y agregar código a nuestro controlador para ese evento. Con $ eval, hay menos acoplamiento entre el controlador y la directiva.
fuente
$last
? No puedo encontrarlo en los documentos. ¿Fue eliminado?$last
se define en el ámbito si unng-repeat
está activo en el elemento.$timeout
.Las respuestas que se han dado hasta ahora solo funcionarán la primera vez que
ng-repeat
se procese , pero si tiene una dinámicang-repeat
, lo que significa que va a agregar / eliminar / filtrar elementos, y debe ser notificado cada vez queng-repeat
se procesa, esas soluciones no funcionarán para usted.Entonces, si necesita que le notifiquen CADA VEZ que
ng-repeat
se vuelve a reproducir y no solo la primera vez, he encontrado una manera de hacerlo, es bastante 'hacky', pero funcionará bien si sabe lo que es haciendo. Use esto$filter
en sung-repeat
antes de usar cualquier otro$filter
:Este será
$emit
un evento llamadongRepeatFinished
cada vez queng-repeat
se procesa.Cómo usarlo:
El
ngRepeatFinish
filtro debe aplicarse directamente a unoArray
o unObject
definido en su$scope
, puede aplicar otros filtros después.Cómo NO usarlo:
No aplique otros filtros primero y luego aplique el
ngRepeatFinish
filtro.¿Cuándo debo usar esto?
Si desea aplicar ciertos estilos CSS en el DOM después de que la lista haya terminado de renderizarse, porque debe tener en cuenta las nuevas dimensiones de los elementos DOM que han sido reproducidos por el
ng-repeat
. (Por cierto: ese tipo de operaciones deben realizarse dentro de una directiva)Qué NO HACER en la función que maneja el
ngRepeatFinished
evento:No realice una
$scope.$apply
función en esa función o colocará Angular en un bucle sin fin que Angular no podrá detectar.No lo use para hacer cambios en las
$scope
propiedades, porque esos cambios no se reflejarán en su vista hasta el próximo$digest
ciclo, y dado que no puede realizar una$scope.$apply
, no serán de ninguna utilidad."¡¡Pero los filtros no están destinados a usarse así !!"
No, no lo son, esto es un truco, si no te gusta, no lo uses. Si conoce una mejor manera de lograr lo mismo, hágamelo saber.
Resumiendo
fuente
$last
elemento también se cambia, langRepeatFinish
directiva simple al verificar$last
ahora funcionará. Tan pronto como se llama ngRepeatFinish, elimino el elemento ficticio. (También lo oculto con CSS para que no aparezca brevemente)Mark Rajcok
funciona perfectamente cada re-render de la ng-repeat (por ejemplo, debido al cambio de modelo) Entonces, esta solución hacky no es necesaria.Si necesita llamar a diferentes funciones para diferentes repeticiones ng en el mismo controlador, puede intentar algo como esto:
La directiva:
En su controlador, capture eventos con $ on:
En su plantilla con múltiples ng-repeat
fuente
Las otras soluciones funcionarán bien en la carga inicial de la página, pero llamar a $ timeout desde el controlador es la única forma de garantizar que se llame a su función cuando cambia el modelo. Aquí hay un violín de trabajo que usa $ timeout. Para su ejemplo sería:
ngRepeat solo evaluará una directiva cuando el contenido de la fila sea nuevo, por lo que si elimina elementos de su lista, onFinishRender no se activará. Por ejemplo, intente ingresar valores de filtro en estos violines emitidos .
fuente
ta
en$scope.$watch("ta",...
?Si no es reacio a usar accesorios de alcance de doble dólar y está escribiendo una directiva cuyo único contenido es una repetición, hay una solución bastante simple (suponiendo que solo le importe el renderizado inicial). En la función de enlace:
Esto es útil para los casos en los que tiene una directiva que necesita manipular DOM en función de los anchos o las alturas de los miembros de una lista representada (que creo que es la razón más probable por la que uno haría esta pregunta), pero no es tan genérica como las otras soluciones que se han propuesto.
fuente
Una solución para este problema con un ngRepeat filtrado podría haber sido con eventos de mutación , pero están en desuso (sin reemplazo inmediato).
Entonces pensé en otra fácil:
Esto se engancha a los métodos Node.prototype del elemento padre con un tiempo de espera $ de una marca para observar modificaciones sucesivas.
Funciona principalmente correcto, pero obtuve algunos casos en los que se llamaría altDone dos veces.
Nuevamente ... agregue esta directiva al padre de ngRepeat.
fuente
appendChild
también (ya que solo uséinsertBefore
yremoveChild
) en el código anterior.Muy fácil, así es como lo hice.
fuente
Por favor, eche un vistazo al violín, http://jsfiddle.net/yNXS2/ . Como la directiva que creó no creó un nuevo ámbito, continué en el camino.
$scope.test = function(){...
Hizo que eso sucediera.fuente
Estoy muy sorprendido de no ver la solución más simple entre las respuestas a esta pregunta. Lo que desea hacer es agregar una
ngInit
directiva en su elemento repetido (el elemento con langRepeat
directiva) buscando$last
(una variable especial establecida en el alcance por langRepeat
cual indica que el elemento repetido es el último en la lista). Si$last
es cierto, representamos el último elemento y podemos llamar a la función que queramos.El código completo para su marcado HTML sería:
No necesita ningún código JS adicional en su aplicación además de la función de alcance que desea llamar (en este caso
test
) , yangInit
que Angular.js lo proporciona. Solo asegúrese de tener sutest
función en el alcance para que se pueda acceder desde la plantilla:fuente