$scope.$просмотр на родительском контроллере не запускается при дочернем ng-select

#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 вчера вечером немного почитал о прототипическом наследовании, и это начинает проясняться. Обнаружил некоторые недоразумения, которые у меня были из-за моего опыта в классическом наследовании. Я начинаю понимать силу и масштаб (каламбур) этого. Спасибо за ваши объяснения, это очень полезно.