Angular — изменения в области действия контроллера директивы не отражаются в представлении.

Изменения в моей переменной области видимости foo обновляются в html. Когда это значение изменяется внутри области действия контроллера директивы, оно не обновляется в html.

Что мне нужно сделать, чтобы он обновился?

У меня есть простой пример:

app.js

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

app.controller('ctrl', function($scope) {
  $scope.foo = 99;

  $scope.changeValue = function() {
    $scope.foo = $scope.foo + 1;
  }
});

app.directive('d1', function(){
  return {
    restrict: 'E',
    scope: {
      theFoo: '='
    },
    templateUrl: 'd1.html',
    controller: 'd1Ctrl',
  }
});

app.controller('d1Ctrl', function($scope) {
  $scope.test = $scope.theFoo;
});

d1.html

<div>
  <p>The value of foo is '{{theFoo}}'.</p>
  <p>The value of test is '{{test}}'.</p>
</div>

внутри index.html

<d1 the-foo='foo'>
</d1>

<button ng-click='changeValue()'>change value</button>

Таким образом, {{theFoo}} обновляется, а {{test}} — нет. Почему?


person PeteGO    schedule 06.10.2016    source источник


Ответы (3)


Причина в том, что значение $scope.foo является примитивным.

В контроллере директив вы назначаете $scope.test только один раз при инициализации контроллера. У примитивов нет наследования, как у объектов, поэтому нет ничего, что могло бы измениться $scope.test после первоначального присваивания.

Если бы вместо этого вы использовали объект для передачи... наследование было бы в силе, и вы бы увидели изменения... в противном случае вам нужно было бы наблюдать $scope.theFoo и обновлять $scope.test самостоятельно.

person charlietfl    schedule 06.10.2016
comment
Это одна из проблем, которые у меня есть с Angular. Хотя использование controller-as, по-видимому, позволяет избежать большинства этих головных болей, поскольку он рассматривается как непримитивный, мне все же не нравится, как мы должны переосмысливать наш способ обновления примитивных значений. - person jusopi; 06.10.2016
comment
Вся проблема @jusopi исчезнет, ​​если вы будете следовать передовым методам и использовать объекты вместо примитивов. Я редко использую $watch в своем коде и удостоверяюсь, что использую свойства объекта в представлении, а не примитивы. - person charlietfl; 06.10.2016
comment
извините, но сказать, что вся проблема исчезает, неправильно. Если он не изменит внутреннюю работу директивы, чтобы получить тестовое значение из непримитивного связанного значения, test по-прежнему не будет обновлен. plnkr.co/edit/bRrQ9z4oBYrdBCLwbOjP?p=preview - person jusopi; 07.10.2016
comment
@jusopi, но он все еще передает примитив, а не объект - person charlietfl; 07.10.2016
comment
Тогда его директива должна будет иметь некоторые знания о передаче не-примитивов. Я думаю, что это плохой дизайн. Я бы предпочел снизить производительность оператора $watch, чем дать директиве знать о свойствах объекта. - person jusopi; 09.10.2016

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

Если вы хотите связать любые последующие изменения, вам нужно установить оператор $watch либо в вашем контроллере, либо в функции ссылки.

$scope.$watch( 'theFoo', function(val){ $scope.test = val; })

обновленный плункер — http://plnkr.co/edit/eWoPutIJrwxZj9XJu6QG?p=preview

person jusopi    schedule 06.10.2016

здесь вы изолировали область действия директивы, поэтому test не отображается для d1.html, если вам нужно изменить test вместе с theFoo, вы должны сначала сделать его видимым для директивы с помощью

app.directive('d1', function(){
  return {
    restrict: 'E',
    scope: {
      theFoo: '=',
      test : '=' //getting test as well
    },
    templateUrl: 'd1.html',
    controller: 'd1Ctrl',
  }
});

а в index.html вы должны передать значение тесту <d1 the-foo='foo' test='foo'></d1>

в приведенном выше коде ваш контроллер не очень полезен, код будет работать нормально даже без этой части controller: 'd1Ctrl'. в этом примере вам не нужно использовать $watch.

person Priyamal    schedule 06.10.2016
comment
Это упрощенный пример для демонстрации моей проблемы — test определен в области действия контроллера директивы, поэтому он должен быть виден. Плюс он изначально получает значение, но не обновляется. - person PeteGO; 07.10.2016