Привязка шаблона директивы Angular не обновляется

у меня есть директива, настроенная здесь http://jsfiddle.net/screenm0nkey/8Cw4z/3 который имеет две привязки к одному и тому же свойству области, но по какой-то причине привязка в свойстве шаблона директивы не обновляется при изменении модели (после ввода ввода).

<test>
    <h3>Inner {{count}}</h3>
    <input type="text" ng-model="count">
</test>

var App = angular.module('App', []);
App.directive('test', function() {
    return {
      restrict: 'E',
      replace: true,
      transclude: true,
      template: "<h1>Outer{{count}} <div ng-transclude></div></h1>",
      controller: function ($scope) {
        $scope.count = 1;
      }
    };
  });

но если я перемещаю входную позицию в разметке, она работает и обе привязки обновление.

<input type="text" ng-model="count">
<test>
     <h3>Inner {{count}}</h3>
</test>

http://jsfiddle.net/screenm0nkey/dCvZk/3

может ли кто-нибудь объяснить, почему позиция ввода, содержащая привязку, повлияет на привязки. Я предположил, что во время цикла дайджеста наблюдатели за обеими привязками будут обновляться независимо от позиции разметки.

большое спасибо

7 ответов


для меня это кажется чисто проблемой области. Давайте посмотрим на разметку, которая формируется как:

не работает:

<body ng-app="App" class="ng-scope">
  <h1 class="ng-binding">Outer1 <div ng-transclude="">
    <h3 class="ng-scope ng-binding">Inner 1</h3>
    <input type="text" ng-model="count" class="ng-scope ng-pristine ng-valid">
    </div>
  </h1>
</body>

работает:

<body ng-app="App" class="ng-scope">
  <input type="text" ng-model="count" class="ng-valid ng-dirty">
  <h1 class="ng-binding">Outer <div ng-transclude="">
    <h3 class="ng-scope ng-binding">Inner </h3>
    </div>
  </h1>
</body>

на ng-scope class является полезным маркером для того, где Angular объявляет новую область.

вы можете видеть по разметке, что в рабочем примере оба count свойства заключены в тег scope, который прилагается к body. Итак, в этом случае directive scope является дочерним элементом body область (и, следовательно, имеет к ней доступ).

однако в Примере, который не работает,Outer1 свойство находится вне области, что input в.

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

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

angular scope heirarchy


короче говоря-как говорили другие, это проблема с областью охвата. Использование директивы "ng-transclude"создает новую область. Когда создается новая область значения из старой области будет доступен в новой области (следовательно, первая замена), но после этого будут обновлены только объекты, которые являются общими между старой / новой областью. Вот почему использование объекта будет работать, но использование значения не будет.

в вашем случае размещение поля ввода внутри ng-transclude заставляет это редактировать только значение в этой области, а не значение в родительской области (из которой извлекается счетчик для директивы "test").

кстати, это может быть проблема с повторителями (ng-repeat), а также другими директивами. Лучше всего использовать такой инструмент, как"бэтаранг" для того, чтобы найти такие вопросы, как этот. Это позволяет посмотреть, что находится в каждой области и определить, почему на экране не отображаются "правильные" данные. Надеюсь, это поможет объяснить дальше!


добавить ng-change to input , Она должна работать. Проблема в том, что контроллер в директиве не знает о count изменить.

JS

var App = angular.module('App', []);

App.directive('test', function () {        
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        template: "<h1>Outer {{this.count}} <div ng-transclude></div></h1>",
        controller: function ($scope) {
            $scope.count = 1;

            $scope.onChange = function(count){          
              $scope.count = count;          
            }
        }       
    };
});

HTML-код

<test>
     <h3>Inner {{count}}</h3>
    <input type="text" ng-model="count" ng-change="onChange(count)">        
</test>

демо Скрипка


порядок имеет значение из-за разницы между созданием собственность в области по сравнению с фактически используя объект привязан к объему (особенно при включение создает новый дочерний scopr). Рекомендуется использовать объект в области и привязывать свойства к этому объекту, когда проблемы области могут вступать в игру с директивами и трансклюдиями.

Если вы измените свой код на это, он будет работать так, как вы ожидали, и порядок не имеет значения. Обратите внимание, что я создаю объект scope и размещение count в качестве свойства на этом объекте.

<test>
    <h3>Inner {{data.count}}</h3>
    <input type="text" ng-model="data.count"/>
</test>

var App = angular.module('App', []);

App.directive('test', function() {
    return {
      restrict: 'E',
      replace: true,
      transclude: true,
      template: "<h1>Outer{{data.count}} <div ng-transclude></div></h1>",
      controller: function ($scope) {
          $scope.data = {};
          $scope.data.count = 1;
      }
    };
  });

Это отличный учебник на эту тему. Реквизит яйцеголовым. https://egghead.io/lessons/angularjs-the-dot


это проблема с охватом.

$scope.count = 1; добавляет в собственность count в область <test> в. Назовем это родительской областью.

ng-transclude создает новую область, назовем ее дочерней областью. Когда <h3>Inner {{count}}</h3> оценивается, дочерняя область не имеет свойства count таким образом, он считывается из родительской области.

<input type="text" ng-model="count"> привязывает значение входного сигнала к свойству count в рамках ребенка. Как только вы введете что-то, свойство будет создано, если его еще нет. С этого момента <h3>Inner {{count}}</h3> получает свое значение из сферы ребенка.

области в angular являются простыми объектами JavaScript и подключены к своим родителям через прототипы. Поэтому, прежде чем вводить что-то, дочерняя область выглядит примерно так:

{
  prototype: { // = parent scope
     count: 1
  }
}

когда вы изменяете значение, скажем, на 5, область выглядит примерно как

{
  count: 5,
  prototype: { // = parent scope
     count: 1
  }
}

потому что привязка данных делает что-то вроде scope.count = 5.


здесь обойти

изменить $scope.count to

$scope.helper = {
    count: 1
}

и рефакторинг остальные.

посмотрите это видео для объяснений.


Кажется, что мы не можем изменить это, так как ngTransclude использовать