javascript - finish - ng-repetir evento final
ng repeat on finish (15)
Aquí hay un enfoque simple utilizando ng-init
que ni siquiera requiere una directiva personalizada. Ha funcionado bien para mí en ciertos escenarios, por ejemplo, la necesidad de desplazar automáticamente una división de elementos repetidos ng a un elemento en particular en la carga de la página, por lo que la función de desplazamiento debe esperar hasta que la ng-repeat
haya terminado de mostrarse al DOM antes de que pueda fuego.
<div ng-controller="MyCtrl">
<div ng-repeat="thing in things">
thing: {{ thing }}
</div>
<div ng-init="fireEvent()"></div>
</div>
myModule.controller(''MyCtrl'', function($scope, $timeout){
$scope.things = [''A'', ''B'', ''C''];
$scope.fireEvent = function(){
// This will only run after the ng-repeat has rendered its things to the DOM
$timeout(function(){
$scope.$broadcast(''thingsRendered'');
}, 0);
};
});
Tenga en cuenta que esto solo es útil para las funciones a las que necesita llamar una vez después de que ng-repeat se reproduzca inicialmente. Si necesita llamar a una función cada vez que se actualicen los contenidos de ng-repeat, tendrá que usar una de las otras respuestas en este hilo con una directiva personalizada.
Quiero llamar a alguna función jQuery que apunta a div con tabla. Esa tabla se llena con ng-repeat
.
Cuando lo llamo
$(document).ready()
No tengo ningún resultado.
también
$scope.$on(''$viewContentLoaded'', myFunc);
no ayuda
¿Hay alguna forma de ejecutar la función justo después de que se complete el llenado de ng-repeat? He leído un consejo sobre el uso de directive
personalizadas, pero no tengo ni idea de cómo usarlo con ng-repeat y mi div ...
Aquí hay una directiva de repetición hecha que llama a una función específica cuando es verdadera. Descubrí que la función llamada debe usar $ timeout con intervalo = 0 antes de realizar la manipulación de DOM, como inicializar información sobre herramientas en los elementos renderizados. jsFiddle: http://jsfiddle.net/tQw6w/
En $ scope.layoutDone, intente comentar la línea de $ timeout y elimine el comentario "¡NO ES CORRECTO!" Línea para ver la diferencia en la información sobre herramientas.
<ul>
<li ng-repeat="feed in feedList" repeat-done="layoutDone()" ng-cloak>
<a href="{{feed}}" title="view at {{feed | hostName}}" data-toggle="tooltip">{{feed | strip_http}}</a>
</li>
</ul>
JS:
angular.module(''Repeat_Demo'', [])
.directive(''repeatDone'', function() {
return function(scope, element, attrs) {
if (scope.$last) { // all are rendered
scope.$eval(attrs.repeatDone);
}
}
})
.filter(''strip_http'', function() {
return function(str) {
var http = "http://";
return (str.indexOf(http) == 0) ? str.substr(http.length) : str;
}
})
.filter(''hostName'', function() {
return function(str) {
var urlParser = document.createElement(''a'');
urlParser.href = str;
return urlParser.hostname;
}
})
.controller(''AppCtrl'', function($scope, $timeout) {
$scope.feedList = [
''http://feeds.feedburner.com/TEDTalks_video'',
''http://feeds.nationalgeographic.com/ng/photography/photo-of-the-day/'',
''http://sfbay.craigslist.org/eng/index.rss'',
''http://www.slate.com/blogs/trending.fulltext.all.10.rss'',
''http://feeds.current.com/homepage/en_US.rss'',
''http://feeds.current.com/items/popular.rss'',
''http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml''
];
$scope.layoutDone = function() {
//$(''a[data-toggle="tooltip"]'').tooltip(); // NOT CORRECT!
$timeout(function() { $(''a[data-toggle="tooltip"]'').tooltip(); }, 0); // wait...
}
})
Complementando la answer de Pavel, algo más legible y fácilmente comprensible sería:
<ul>
<li ng-repeat="item in items"
ng-init="$last ? doSomething() : angular.noop()">{{item}}</li>
</ul>
¿Por qué más crees que angular.noop
está ahí en primer lugar ...?
Ventajas:
No tienes que escribir una directiva para esto ...
De hecho, debe usar directivas, y no hay ningún evento vinculado al final de un bucle ng-Repeat (ya que cada elemento se construye individualmente y tiene su propio evento). Pero a) el uso de directivas puede ser todo lo que necesita y b) hay algunas propiedades específicas de ng-Repeat que puede usar para que su evento "on ngRepeat completed".
Específicamente, si todo lo que desea es diseñar / agregar eventos a toda la tabla, puede hacerlo usando una directiva que abarque todos los elementos ngRepeat. Por otro lado, si desea abordar cada elemento específicamente, puede usar una directiva dentro de ngRepeat, y actuará en cada elemento, una vez que se haya creado.
Luego, están las propiedades $index
, $first
, $middle
y $last
que puede usar para desencadenar eventos. Así que para este HTML:
<div ng-controller="Ctrl" my-main-directive>
<div ng-repeat="thing in things" my-repeat-directive>
thing {{thing}}
</div>
</div>
Puedes usar directivas como esta:
angular.module(''myApp'', [])
.directive(''myRepeatDirective'', function() {
return function(scope, element, attrs) {
angular.element(element).css(''color'',''blue'');
if (scope.$last){
window.alert("im the last!");
}
};
})
.directive(''myMainDirective'', function() {
return function(scope, element, attrs) {
angular.element(element).css(''border'',''5px solid red'');
};
});
Encontré una respuesta bien practicada here , pero aún era necesario agregar un retraso.
Crea la siguiente directiva:
angular.module(''MyApp'').directive(''emitLastRepeaterElement'', function() {
return function(scope) {
if (scope.$last){
scope.$emit(''LastRepeaterElement'');
}
}; });
Agrégalo a tu repetidor como un atributo, como este:
<div ng-repeat="item in items" emit-last-repeater-element></div>
Según Radu ,:
$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => {mycode});
Para mí funciona, pero todavía necesito agregar un setTimeout
$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => {
setTimeout(function() {
mycode
}, 100); });
Esta es una mejora de las ideas expresadas en otras respuestas para mostrar cómo obtener acceso a las propiedades ngRepeat ($ index, $ first, $ middle, $ last, $ even, $ odd) al usar la sintaxis declarativa y el alcance de aislamiento ( Google recomienda la mejor práctica) con un elemento-directiva. Note la diferencia principal: scope.$parent.$last
.
angular.module(''myApp'', [])
.directive(''myRepeatDirective'', function() {
return {
restrict: ''E'',
scope: {
someAttr: ''=''
},
link: function(scope, element, attrs) {
angular.element(element).css(''color'',''blue'');
if (scope.$parent.$last){
window.alert("im the last!");
}
}
};
});
Lo hice de esta manera.
Crear la directiva
function finRepeat() {
return function(scope, element, attrs) {
if (scope.$last){
// Here is where already executes the jquery
$(document).ready(function(){
$(''.materialboxed'').materialbox();
$(''.tooltipped'').tooltip({delay: 50});
});
}
}
}
angular
.module("app")
.directive("finRepeat", finRepeat);
Después de agregarlo en la etiqueta donde se encuentra esta repetición
<ul>
<li ng-repeat="(key, value) in data" fin-repeat> {{ value }} </li>
</ul>
Y listo, se ejecutará al final de la repetición ng.
Me gustaría agregar otra respuesta, ya que las respuestas anteriores consideran que el código necesario para ejecutarse después de que se realiza ngRepeat es un código angular, que en ese caso todas las respuestas anteriores ofrecen una solución excelente y simple, algunas más genéricas que otras. y en caso de que sea importante la etapa del ciclo de vida del resumen, puedes echarle un vistazo al blog de Ben Nadel , con la excepción de usar $ parse en lugar de $ eval.
pero en mi experiencia, como dice el OP, normalmente se ejecutan algunos complementos o métodos de JQuery en el DOM compilado de manera final, que en ese caso encontré que la solución más simple es crear una directiva con un setTimeout, ya que la función setTimeout es empujada Al final de la cola del navegador, siempre es correcto después de que todo se hace en angular, normalmente ngReapet, que continúa después de su función de enlace posterior de los padres.
angular.module(''myApp'', [])
.directive(''pluginNameOrWhatever'', function() {
return function(scope, element, attrs) {
setTimeout(function doWork(){
//jquery code and plugins
}, 0);
};
});
para quienquiera que se pregunte que en ese caso, ¿por qué no usar $ timeout, es que causa otro ciclo de resumen que es completamente innecesario?
No es necesario crear una directiva, especialmente para tener un evento completo de ng-repeat
.
ng-init
hace la magia por ti.
<div ng-repeat="thing in things" ng-init="$last && finished()">
el $last
se asegura de que el finished
solo se active cuando el último elemento se haya procesado en el DOM.
No te olvides de crear el evento $scope.finished
.
Feliz codificacion !!
EDITAR: 23 de octubre de 2016
En caso de que también desee llamar a la función finished
cuando no haya ningún elemento en la matriz, puede utilizar la siguiente solución
<div style="display:none" ng-init="things.length < 1 && finished()"></div>
//or
<div ng-if="things.length > 0" ng-init="finished()"></div>
Solo agregue la línea anterior en la parte superior del elemento ng-repeat
. Verificará si la matriz no tiene ningún valor y llamará a la función en consecuencia.
P.ej
<div ng-if="things.length > 0" ng-init="finished()"></div>
<div ng-repeat="thing in things" ng-init="$last && finished()">
Si simplemente desea cambiar el nombre de la clase para que se represente de manera diferente, el código que aparece debajo hará el truco.
<div>
<div ng-show="loginsuccess" ng-repeat="i in itemList">
<div id="{{i.status}}" class="{{i.status}}">
<div class="listitems">{{i.item}}</div>
<div class="listitems">{{i.qty}}</div>
<div class="listitems">{{i.date}}</div>
<div class="listbutton">
<button ng-click="UpdateStatus(i.$id)" class="btn"><span>Done</span></button>
<button ng-click="changeClass()" class="btn"><span>Remove</span></button>
</div>
<hr>
</div>
Este código funcionó para mí cuando tuve un requisito similar para representar el artículo comprado en mi lista de compras en fuente de Strick.
Si simplemente desea ejecutar algún código al final del bucle, aquí hay una variación un poco más simple que no requiere manejo adicional de eventos:
<div ng-controller="Ctrl">
<div class="thing" ng-repeat="thing in things" my-post-repeat-directive>
thing {{thing}}
</div>
</div>
function Ctrl($scope) {
$scope.things = [
''A'', ''B'', ''C''
];
}
angular.module(''myApp'', [])
.directive(''myPostRepeatDirective'', function() {
return function(scope, element, attrs) {
if (scope.$last){
// iteration is complete, do whatever post-processing
// is necessary
element.parent().css(''border'', ''1px solid black'');
}
};
});
Tal vez un enfoque un poco más simple con ngInit
y el método de rebote de debounce
sin la necesidad de una directiva personalizada:
Controlador:
$scope.items = [1, 2, 3, 4];
$scope.refresh = _.debounce(function() {
// Debounce has timeout and prevents multiple calls, so this will be called
// once the iteration finishes
console.log(''we are done'');
}, 0);
Modelo:
<ul>
<li ng-repeat="item in items" ng-init="refresh()">{{item}}</li>
</ul>
Actualizar
Existe una solución AngularJS pura aún más simple que utiliza un operador ternario:
Modelo:
<ul>
<li ng-repeat="item in items" ng-init="$last ? doSomething() : null">{{item}}</li>
</ul>
Tenga en cuenta que ngInit utiliza la fase de compilación previa al enlace, es decir, la expresión se invoca antes de que se procesen las directivas secundarias. Esto significa que aún se puede requerir un procesamiento asíncrono.
También puede ser necesario cuando verifique el scope.$last
variable para envolver su activador con un setTimeout(someFn, 0)
. Un setTimeout 0
es una técnica aceptada en javascript y era imperativo para que mi directive
ejecute correctamente.
Tuve que renderizar fórmulas usando MathJax después de que ng-repeat finalice, ninguna de las respuestas anteriores resolvió mi problema, así que hice lo siguiente. No es una buena solución , pero funcionó para mí ...
<div ng-repeat="formula in controller.formulas">
<div>{{formula.string}}</div>
{{$last ? controller.render_formulas() : ""}}
</div>
<div ng-repeat="i in items">
<label>{{i.Name}}</label>
<div ng-if="$last" ng-init="ngRepeatFinished()"></div>
</div>
Mi solución fue agregar un div para llamar a una función si el elemento era el último en una repetición.