НГ-повторите событие финиша
Я хочу вызвать некоторую функцию jQuery targeting div с таблицей. Эта таблица заполняется ng-repeat.
когда я вызываю его на
$(document).ready()
у меня нет результата.
и
$scope.$on('$viewContentLoaded', myFunc);
не помогает.
есть ли способ выполнить функцию сразу после завершения ng-repeat population? Я прочитал совет об использовании custom directive, но я понятия не имею, как использовать его с ng-repeat и моим div...
15 ответов:
действительно, Вы должны использовать директивы, и нет никакого события, привязанного к концу цикла ng-Repeat (поскольку каждый элемент строится индивидуально и имеет свое собственное событие). Но a) использование директив может быть все, что вам нужно, и b) есть несколько ng-Repeat конкретных свойств, которые вы можете использовать, чтобы сделать ваше событие "on ngRepeat finished".
в частности, если все, что вы хотите, это стиль/добавить события ко всей таблице, вы можете сделать это с помощью директивы, которая охватывает все ngRepeat элементы. С другой стороны, если вы хотите обратиться к каждому элементу конкретно, вы можете использовать директиву внутри ngRepeat, и она будет действовать на каждый элемент после его создания.
то есть
$index,$first,$middleи$lastсвойства можно использовать для запуска событий. Так что для этого HTML:<div ng-controller="Ctrl" my-main-directive> <div ng-repeat="thing in things" my-repeat-directive> thing {{thing}} </div> </div>вы можете использовать такие директивы:
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'); }; });увидеть его в действии в этом Plunker. Надеюсь, это поможет!
Если вы просто хотите выполнить некоторый код в конце цикла, вот немного упрощенный вариант, который не требует дополнительной обработки события:
<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'); } }; });
нет необходимости создавать директиву, особенно для того, чтобы иметь
ng-repeatсобытие Complete.
ng-initделает чудеса для вас.<div ng-repeat="thing in things" ng-init="$last && finished()">the
$lastудостоверяется, чтоfinishedсрабатывает только тогда, когда последний элемент был визуализирован в DOM.не забудьте создать
$scope.finishedсобытие.Удачи В Кодировании!!
EDIT: 23 Oct 2016
в случае, если вы также хотите позвонить
finishedфункция когда нет элемента в массиве, то вы можете использовать следующее решение<div style="display:none" ng-init="things.length < 1 && finished()"></div> //or <div ng-if="things.length > 0" ng-init="finished()"></div>просто добавить эту строку в верхней части
ng-repeatэлемент. Он будет проверять, если массив не имеет никакого значения и вызвать функцию соответственно.например.
<div ng-if="things.length > 0" ng-init="finished()"></div> <div ng-repeat="thing in things" ng-init="$last && finished()">
вот директива repeat-done, которая вызывает указанную функцию, когда true. Я обнаружил, что вызываемая функция должна использовать $timeout с интервалом=0 Перед выполнением манипуляций DOM, таких как инициализация всплывающих подсказок на визуализируемых элементах. jsFiddle: http://jsfiddle.net/tQw6w/
в $ scope.layoutDone, попробуйте закомментировать строку $ timeout и раскомментировать "не правильно!"линия, чтобы увидеть разницу в подсказки.
<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... } })
вот простой подход с использованием
ng-initдля этого даже не требуется пользовательская директива. Это хорошо работало для меня в некоторых сценариях, например, нужно автоматически прокручивать div ng-повторяющихся элементов до определенного элемента При загрузке страницы, поэтому функция прокрутки должна ждать, покаng-repeatзакончил рендеринг в DOM, прежде чем он может стрелять.<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); }; });обратите внимание, что это полезно только для функций, которые вам нужно вызвать один раз после того, как ng-repeat изначально отображается. Если вам нужно вызвать функцию всякий раз, когда содержимое ng-repeat обновляется, вам придется использовать один из других ответов в этом потоке с пользовательской директивой.
дополнение ответ, что - то более читаемое и легко понятное было бы:
<ul> <li ng-repeat="item in items" ng-init="$last ? doSomething() : angular.noop()">{{item}}</li> </ul>Почему ты думаешь
angular.noopесть в первую очередь...?плюсы:
вам не нужно писать директиву для этого...
может быть, немного проще подход с
ngInitи Лодашь этоdebounceметод без необходимости пользовательской директивы:
это также может быть необходимо при проверке
scope.$lastпеременная, чтобы обернуть триггер сsetTimeout(someFn, 0). АsetTimeout 0это принятая техника в javascript, и это было необходимо для моегоdirectiveдля правильной работы.
это улучшение идей, выраженных в других ответах, чтобы показать, как получить доступ к свойствам ngRepeat ($index, $first, $middle, $last, $even, $odd) при использовании декларативного синтаксиса и изолировать область (рекомендуемая Google лучшая практика) с директивой элемента. Обратите внимание на основное различие:
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!"); } } }; });
Я хотел бы добавить еще один ответ, поскольку предыдущие ответы предполагают, что код, необходимый для запуска после выполнения ngRepeat, является угловым кодом, который в этом случае все ответы выше дают отличное и простое решение, некоторые более общие, чем другие, и в случае его важного этапа жизненного цикла дайджеста вы можете взглянуть на блог Бена надела об этом, за исключением использования $parse вместо $eval.
но по моему опыту, как утверждает OP, его обычно выполняется некоторые jQuery плагины или способы на любом составленном дом, который в таком случае я нашел, что наиболее простым решением является создание директивы с помощью setTimeout, с помощью setTimeout функция получает толкнул на конец очереди в браузере, ее всегда правы, ведь все делается в угловой, как правило, ngReapet которое продолжается после того, как его родители postLinking функция
angular.module('myApp', []) .directive('pluginNameOrWhatever', function() { return function(scope, element, attrs) { setTimeout(function doWork(){ //jquery code and plugins }, 0); }; });для тех, кто задается вопросом, что в этом случае почему бы не использовать $timeout, это то, что он вызывает еще один цикл дайджеста, который совершенно не нужен
Я сделал это таким образом.
создать директиву
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);после того, как вы добавите его на этикетке, где это ng-repeat
<ul> <li ng-repeat="(key, value) in data" fin-repeat> {{ value }} </li> </ul>и готовый с этим будет запущен в конце ng-повтора.
<div ng-repeat="i in items"> <label>{{i.Name}}</label> <div ng-if="$last" ng-init="ngRepeatFinished()"></div> </div>мое решение состояло в том, чтобы добавить div для вызова функции, если элемент был последним в повторе.
мне пришлось отображать формулы с помощью MathJax после окончания ng-repeat, ни один из приведенных выше ответов не решил мою проблему, поэтому я сделал, как показано ниже. Это не очень хорошее решение, но работал для меня...
<div ng-repeat="formula in controller.formulas"> <div>{{formula.string}}</div> {{$last ? controller.render_formulas() : ""}} </div>
Я нашел ответ здесь хорошо практиковался, но надо было еще добавить задержку
создайте следующую директиву:
angular.module('MyApp').directive('emitLastRepeaterElement', function() { return function(scope) { if (scope.$last){ scope.$emit('LastRepeaterElement'); } }; });добавьте его в свой ретранслятор в качестве атрибута, например:
<div ng-repeat="item in items" emit-last-repeater-element></div>согласно Раду,:
$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => {mycode});для меня это работает, но мне все равно нужно добавить setTimeout
$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => { setTimeout(function() { mycode }, 100); });
Если вы просто хотите изменить имя класса, чтобы он отображался по-другому, ниже код будет делать трюк.
<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>этот код работал для меня, когда у меня было аналогичное требование для отображения купленного элемента в моем списке покупок в шрифте Strick trough.
Comments