Подтвердить что ты не робот

AngularJS не обновляется ngRepeat при обновлении массива

У меня возникают серьезные проблемы с пониманием AngularJS. Итак, у меня есть базовый массив в моем контроллере, например

$scope.items = ["a","b","c"]

Я ngRepeating в моем шаблоне над массивом элементов ng-repeat = "item in items". Супер прямолинейный до сих пор. После нескольких действий UX, я хочу подтолкнуть некоторые новые вещи к моему массиву.

 $scope.items.push("something");

Итак, 50% времени, новый элемент добавляется в представление. Но остальные 50% ничего не происходит. И это как супер разочарование; bc, если я обернул это значение в $scope. $apply(), я получил ошибку "$ digest is in progress". Обертка в $timeout также не помогает.

И когда я проверяю область своего элемента с помощью расширения Chrome; Я вижу, что новые данные есть, и значение $scope.items верное. Но мнение просто не заботится о добавлении этого в DOM.

Спасибо!

4b9b3361

Ответ 1

Вы изменяете область вне цикла angular $digest в 50% случаев.

Если есть обратный вызов, который не является угловым; (posicbly jquery). Вы должны вызвать $apply, чтобы принудительно выполнить цикл $digest. Но вы не можете вызвать $apply в цикле $digest, потому что каждое сделанное вами изменение будет автоматически отражено.

Вам нужно знать, когда обратный вызов не от angular и должен вызывать $apply только тогда.

Если вы не знаете и не можете учиться, вот аккуратный трюк:

var applyFn = function () {
    $scope.someProp = "123";
};
if ($scope.$$phase) { // most of the time it is "$digest"
    applyFn();
} else {
    $scope.$apply(applyFn);
}

Ответ 2

Как указано Umur Kontacı, вы иногда делаете изменения модели вне цикла дайджеста. Однако вместо того, чтобы обойти эту проблему и пытаться определить, находитесь ли вы в контексте приложения/дайджест или нет, я предлагаю вам убедиться, что этого никогда не произойдет.

Основной причиной этой проблемы является то, что ваша функция называется реакцией на событие DOM. Например.

jQuery('.some-element').click(function() { seeminglyProblematicCode() })

Здесь вам нужно использовать $apply(), а не внутри функции. В противном случае весь ваш код будет усеян такими различиями рано или поздно. Предполагая, что в контексте этого обработчика существует область видимости, вы можете написать:

jQuery('.some-element').click(function() { 
    $scope.$apply(function() { seeminglyProblematicCode() })
})

Однако есть одна оговорка, о которой вы должны знать: когда вы вызываете событие click из вашего кода, вы столкнетесь с проблемой, что цикл дайджеста уже выполняется. Здесь вам понадобится $timeout. Ответ на этот вопрос очень хорошо освещает эту проблему.

Ответ 3

У меня была такая же проблема, и я решил проверить, какие контроллеры вызываются во вложенных директивах.

# Parent Controller
app.controller 'storeController', ($scope, products) ->

  $scope.cart = ["chicken", "pizza"]
  $scope.addToCart = (item) ->
    $scope.cart.push item

  # from service
  products.get().then (items) ->
    $scope.products = items

# Parent Directives
app.directive 'storeContainer', ($scope, config) ->
  restrict: 'E'
  templatUrl: 'store-container.html'
  controller: 'storeController'

# Nested Directive
app.directive 'storeFront', ($scope, config) ->
  restrict: 'E'
  templatUrl: 'store-front.html'
  controller: 'storeController'

# Parent Template templates/directives/store-container.html
<div ng-repeat="item in cart">{{ item }}</div>
<strore-front></store-front>

# Nested Template templates/directives/store-front.html
<ul ng-repeat="item in products">
  <li ng-click"addToCart(item)">{{ item }}</li>
</ul>

Ошибка здесь вложенная директива создает второй контроллер в цепочке прототипов (дубликат storeController), к которому у родительского шаблона нет доступа. Чтобы разрешить запись вложенного контроллера следующим образом:

# Nested Directive
app.directive 'storeFront', ($scope, config) ->
  restrict: 'E'
  templatUrl: 'store-front.html'

Есть более эффективные способы создания цепочки наследования, но это решит проблему для многих людей, изучающих AngularJS.