Почему моя вложенная директива отключается от своей ngModel, как только вызывается $setViewValue()?

Планкер здесь.

У меня есть директива ("дочерняя"), вложенная в другую директиву ("родительскую"). Это requires ngModel, а ngModelCtrl.$modelValue отображается и поддерживается в актуальном состоянии в своем шаблоне. То есть, пока я не вызову ngModelCtrl.$setViewValue().

Итак, вот HTML, инициализирующий директивы:

<div parent>
  <div child ng-model="content">Some</div>
</div>

А вот и директивы:

angular.module('form-example2', [])
  .controller('MainCtrl', function($scope){
  $scope.content = 'Hi';
})
.directive('parent', function() {
  return {
    transclude: true,
    template: '<div ng-transclude></div>',
    controller: function(){
    },
    scope: {}
  };
})
.directive('child', function() {
  return {
    require: ['ngModel', '^parent'],
    transclude: true,
    template: '<div>Model: {{model.$modelValue}} (<a style="text-decoration: underline; cursor: pointer;" ng-click="alter()">Alter</a>)<br />Contents: <div style="background: grey" ng-transclude></div></div>',
    scope: {},
    link: function(scope, elm, attrs, ctrl) {
      var ngModelCtrl = ctrl[0];
      var parentCtrl = ctrl[1];

      scope.model = ngModelCtrl;

      // view -> model
      scope.alter = function(){
        ngModelCtrl.$setViewValue('Hi2');
      }

      // model -> view

      // load init value from DOM
    }
  };
});

Когда модель (т.е. content) изменяется, это изменение можно увидеть внутри дочерней директивы. Когда вы нажимаете ссылку «Изменить» (которая запускает вызов $setViewValue()), значение модели должно стать «Hi2». Это правильно отображается внутри директивы child, но не в модели вне директивы. Кроме того, когда я теперь обновляю модель вне директивы, она больше не обновляется внутри директивы.

Как так?


person Vincent    schedule 29.10.2014    source источник


Ответы (1)


Директивы оказались в порядке; единственная проблема заключалась в том, что передаваемая модель должна быть свойством объекта. Следовательно, директивы работают, если в вызывающий код внесены следующие изменения (Plunker):

В контроллере вместо $scope.content = 'Hi';:

$scope.content = {
  value: 'Hi'
};

В шаблоне замените все ссылки на content на content.value:

<input ng-model="content.value" type="text" />
<div parent>
  <div child ng-model="content.value">Some</div>
  </div>
<pre>model = {{content.value}}</pre>

Причина, по которой это работает, заключается в том, что когда Angular передает ссылку на модель во включенную область действия родительской директивы (т. является копией, изменения которой Angular не может отслеживать.

Ответ @Josep очень помог, поэтому, хотя он и не дал фактического решения, если вы читаете это и это полезно, проголосуйте за него :)

person Vincent    schedule 30.10.2014
comment
Спасибо за обновления. Итак, если это утверждение неверно, по какой причине его изменение, как показано выше, решает проблему? Кроме того, когда ngModel привязывается к текущей области, не является ли она в этом случае дочерней областью контроллера? Поскольку включение родительской директивы делает область включенного содержимого родственной области действия родительской директивы. И это должно означать, что content по-прежнему относится к модели контроллера, верно? - person Vincent; 30.10.2014
comment
Я определенно хочу понять, поэтому и задаю все эти вопросы :) Так что то, что вы говорите о scope.model = ngModelCtrl;, имеет смысл. Однако, когда я этого не делаю (что действительно чище), он все равно не работает с примитивными моделями: plnkr.co/edit/oAJ7cvWSj1PmHbA7VL36?p=preview Вы знаете, почему это так? Кроме того, вы удалили свой ответ? :( - person Vincent; 30.10.2014