Как "распаковать" выражение
скажем, у меня есть ng-повтор с большим массивом.
при запуске ng-repeat он добавляет каждый элемент этого массива в изолированную область, а также сам массив в области. Это означает, что $digest проверяет весь массив на наличие изменений, и кроме того, он проверяет каждый отдельный элемент в этом массиве для изменений.
посмотреть этот plunker как пример, о чем я говорю.
в моем случае, я никогда не изменить один элемент моего массива, поэтому мне не нужно, чтобы за ними наблюдали. Я буду только когда-либо изменять весь массив, и в этом случае ng-repeat будет повторно отображать таблицу целиком. (Если я ошибаюсь, пожалуйста, дайте мне знать..)
в массиве (скажем) 1000 строк, это еще 1000 выражений, которые мне не нужно оценивать.
как я могу отменить регистрацию каждого элемента из наблюдателя, все еще наблюдая за основным массивом?
вместо дерегистрация я мог бы иметь больше контроля над моим $ digest и как-то пропустить каждую отдельную строку?этот конкретный случай является примером более общей проблемы. Я знаю, что $watch возвращает функцию 'deregisteration', но это не помогает, когда директива регистрирует часы, что происходит большую часть времени.
5 ответов:
чтобы иметь ретранслятор с большим массивом, который вы не смотрите, чтобы смотреть каждый элемент.
вам нужно будет создать пользовательскую директиву, которая принимает один аргумент и выражение для вашего массива, а затем в функции связывания вы просто смотрите этот массив, и у вас будет функция связывания программно обновить HTML (а не использовать ng-repeat)
что-то вроде (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>'); }); }); } }; });
... что кажется болью в сердце торец.
альтернативный хакерский метод
вы могли бы перебрать
$scope.$$watchers
и изучить$scope.$$watchers[0].exp.exp
чтобы увидеть, соответствует ли оно выражению, которое вы хотите удалить, затем удалите его с помощью простогоsplice()
звонок. Пита здесь, это такие вещи, какBlah {{whatever}} Blah
между тегами будет выражение, и даже будет включать в себя возврат каретки.С другой стороны, вы можете просто перебрать $ scope вашего ng-repeat и просто удалить все, а затем явно добавить часы, которые вы хотите... Я не знаю.
в любом случае, это похоже на халтуру.
чтобы удалить наблюдатель, сделанный $scope.$смотреть
вы можете отменить регистрацию a
$watch
С функцией возвращаемых$watch
звоните:например, иметь
$watch
только огонь один раз:var unregister = $scope.$watch('whatever', function(){ alert('once!'); unregister(); });
вы можете, конечно, вызвать функцию отменить в любое время вы хотите... это было просто образец.
вывод: на самом деле нет отличного способа сделать именно то, что вы просите
но одна вещь, чтобы рассмотреть: это даже не стоит обращать внимания? Кроме того, действительно ли это хорошая идея, чтобы тысячи записей загружались в десятки куполов каждый? Пища для размышлений.
Я надеюсь, что это поможет.
EDIT 2 (удалена плохая идея)
$watch возвращает функцию, которая развязывает $watch при вызове. Так что это все, что вам нужно для "watchOnce":
var unwatchValue = scope.$watch('value', function(newValue, oldValue) { // Do your thing unwatchValue(); });
изменить: см. другой ответ, который я опубликовал.
Я пошел и реализовал идею блеша отдельным способом. Мой
ngOnce
директива просто уничтожает дочернюю область, котораяngRepeat
создает на каждом элементе. Это означает, что область не получает доступ от своих родителейscope.$digest
и наблюдатели никогда не исполняются.сама директива:
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); } } }; }]);
используя это:
<li ng-repeat="item in contents" ng-once> {{item.title}}: {{item.text}} </li>
Примечание
ng-once
не создает свою собственную область действия, что означает, что она может влиять на родственные элементы. Все они делают одно и то же:<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>
Примечаниеэто может быть плохая идея
если вы используете
angularjs 1.3
или выше, вы можете использовать синтаксис single bind как<li ng-repeat="item in ::contents">{{item}}</li>
это свяжет значение и удалит наблюдателей после запуска первого цикла дайджеста и изменения значения от
undefined
доdefined
в первый раз.очень полезным блог об этом.