#javascript #angularjs
#javascript #angularjs
Вопрос:
Пример использования
Используя a, select
который привязан к переменной контроллера, всякий раз, когда переменная существует в родительском контроллере и $watch
создается для этой переменной в родительском, родительский $watch
не запускается. Почему это происходит?
Код
Служебная функция генератора случайных данных
Этот код не важен, но включен для наглядности.
function populate(x) {
var items = [];
for (var i = 0; i < x; i ) {
items.push( { label: 'item ' i,
data: { value: 'some value ' i },
id: i });
}
return items;
};
Родительский контроллер
function parent($scope) {
$scope.items = populate(10);
$scope.selected = $scope.items[0];
$scope.fired = 0;
$scope.$watch('selected.id', function(id) {
$scope.fired ;
});
};
Дочерний контроллер
function child($scope) {
};
Сценарий 1
Этот сценарий работает так, как описано. В этом случае переменная $scope.fired
будет увеличиваться всякий раз, когда пользователь изменяет значение выбора. jsFiddle
Вид
<div ng-app>
<div ng-controller="parent">
<select ng-model="selected"
ng-options="item as item.label for item in items">
</select>
<pre>
{{ fired | json }}
</pre>
<pre>
{{ selected | json }}
</pre>
</div>
</div>
Сценарий 2
В следующем сценарии $watch
не будет запускаться в родительском контроллере. Однако, если $watch
переместить на дочерний контроллер, он сработает. Примечание: изменение в строке 3 по сравнению с приведенным выше кодом. jsFiddle
Вид
<div ng-app>
<div ng-controller="parent">
<div ng-controller="child">
<select ng-model="selected"
ng-options="item as item.label for item in items">
</select>
<pre>
{{ fired | json }}
</pre>
<pre>
{{ selected | json }}
</pre>
</div>
</div>
</div>
Вопрос
Почему включение дочернего контроллера приводит к тому, что $watch
не запускается, даже если дочерний контроллер наследует $scope
?
Ответ №1:
Родительский selected
не меняется сам по себе. Дочерняя область selected
является. Вот почему watch работает не так, как вы ожидали. Это связано с прототипным наследованием.
$watch
Сам должен быть определен в дочерней области, независимо от того, что родительская область является той, которая объявляет ее в первую очередь.
Комментарии:
1. О боже! Прототипное наследование! Таким образом, дочерний контроллер создает только копию полей и методов, но не прослушиватели событий и просмотры?
2. Он не создает копию полей. Когда он ищет поле, он проходит цепочку прототипов и возвращает ссылку (если найден)
3. @Gamb Я провел быстрый тест , это потому, что
ng-select
создается изолированная область? Я не понимаю,increase()
функция обновит родительскийfired
. Похоже, что они оба используют одно и то жеfired
, но имеют свои собственныеselected
.4. На самом деле, @Pete, похоже, ограничен ближайшей областью (в данном случае дочерней). Если вы изменили
ng-model
атрибут на$parent.selected
now, оба контроллера будут иметь обновленное значение, и наблюдение также будет работать (ваш счетчик будет увеличен в два раза). Прототипное наследование запускается, когда вы указываете на родительский элемент напрямую.5. @Gamb вчера вечером немного почитал о прототипическом наследовании, и это начинает проясняться. Обнаружил некоторые недоразумения, которые у меня были из-за моего опыта в классическом наследовании. Я начинаю понимать силу и масштаб (каламбур) этого. Спасибо за ваши объяснения, это очень полезно.