Приоритет привязки атрибута Angularjs

У нас есть следующая директива:

angular.module('app', [])
  .directive('dIsolatedWorks', function() {
    return {
      scope: {
        prop: '='
      },
      template: '<span>{{name}}: {{prop}}</span>',
      link: function(scope) {
        scope.name = 'isolated';
        scope.prop = 'link';
      }
    };
  })
  .directive('dIsolated', function() {
    return {
      scope: {
        prop: '@'
      },
      template: '<span>{{name}}: {{prop}}</span>',
      controller: function($scope) {
        $scope.prop = 'controller';
      },
      link: function(scope) {
        scope.name = 'isolated';
        scope.prop = 'link';
      }
    };
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div d-isolated-works prop="attribute"></div>
  <div d-isolated prop="attribute"></div>
</div>

На самом деле во время реализации я был уверен, что назначение scope.prop поле изменит переменную и будет отображаться как 'link' не 'attribute', Но в настоящее время мы видим, что реальная стоимость будет isolated: attribute, Однако это может быть просто исправлено путем изменения назначения строки для назначения объекта.

Можете ли вы объяснить такое поведение?

3 ответа

Решение

Поэтому, изучив код angularjs для ответа, я нашел правильный - согласно angular.js v1.3.20 у нас есть следующие строки кода в функции связывания для @ атрибуты (строка 7698):

      case '@':
            attrs.$observe(attrName, function(value) {
              isolateBindingContext[scopeName] = value;
            });
            attrs.$$observers[attrName].$$scope = scope;
            if (attrs[attrName]) {
              // If the attribute has been provided then we trigger an interpolation to ensure
              // the value is there for use in the link fn
              isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
            }
            break;

Согласно этому коду

  1. Angularjs регистрирует $ Наблюдатель для атрибута (evalAsync, таким образом, он будет выполнен после завершения цепочки кода)
  2. Значение правильно передается из атрибута, и поэтому мы увидим его значение в функции связывания
  3. Функция связывания распространяется со значением атрибута.
  4. Функция связывания меняет значение пропа и завершает свою работу
  5. Выполнение возвращается к функции $ наблюдателя (потому что она должна выполняться хотя бы один раз)
  6. $ Наблюдатель выполняется, и он меняет значение обратно на значение атрибута

В результате мы можем сказать, что использование строковых параметров в теле директивы допускается только как значение только для чтения, пока оно не будет заключено в блок тайм-аута (или любое другое с отложенным выполнением)

Незначительные изменения дают одинаковые результаты с обоими префиксами = и @

angular.module('app', [])
.directive('dIsolatedWorks', function () {
return {
    scope: {
        prop: '='
    },
    template: '<span>{{name}}: {{prop}}</span>',
    link: function (scope) {
        scope.name = 'isolated';
        scope.prop = 'link';
    }
};
})
.directive('dIsolated', function ($timeout) {
return {
    scope: {
        prop: '@'
    },
    template: '<span>{{name}}: {{prop}}</span>',
    controller: function ($scope) {
        $scope.prop = 'controller';
    },
    link: function (scope, element, attr) {
        scope.name = 'isolated';
        $timeout(function(){  });
        $timeout(function(){
            console.log('Still I found attrib value: ',scope.prop);
          
          scope.prop = 'link'; // this will change it
            });
        //scope.prop = 'link';
     
    }
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
    <div d-isolated-works prop="attribute"></div>
    <div d-isolated prop="attribute"></div>
</div>

Но концептуально

@ привязка для передачи строк. Эти строки поддерживают выражения {{}} для интерполированных значений. Например: . Интерполированное выражение оценивается по родительской области действия директивы.

= связывание для двусторонней привязки модели. Модель в родительской области видимости связана с моделью в изолированной области действия директивы. Изменения в одной модели влияют на другую, и наоборот.

Помня вышеупомянутые понятия, Анализ:

1 - когда мы определяем область видимости с помощью префикса '@', шаблон всегда получает значение из атрибута link scope.prop ничего не влияет)

2 - затем создает scope и присваивает ему строковое значение атрибута

Но

3 - когда будет запущен второй цикл дайджеста (включен ng-click или же ng-model или же $timeout) Это изменит значение

4 - см. $timeout в приведенном выше коде для понимания (Run It!)

Счастливая помощь!

Я полагаю, что параметры в области видимости изолируются ПОСЛЕ фазы соединения. Вот почему вы получаете значение, переданное через атрибут prop, а не то, которое вы задали в функции link.

Не могу найти в документах, как я сказал ( https://docs.angularjs.org/guide/compiler), но провел небольшой эксперимент, который это доказал.

Проверьте скрипку - я только что инициировал свойство 'attribute' в родительской области, и 'dIsolatedWorks' работал аналогично 'dIsolated'

<div ng-app="app">
    {{attribute = 'hello world';}}

    <div d-isolated-works prop="attribute"></div>
    <div d-isolated prop="attribute"></div>
</div>

http://jsfiddle.net/ndfqruxf/

Причина, по которой директива 'dIsolatedWorks' работала так, как вы ожидаете, заключается в том, что для нее была настроена двусторонняя привязка ('='), но в родительской области действия с именем "attribute" не было переменной. Поэтому директива dIsolatedWorks инициировала переменную.

Другие вопросы по тегам