Приоритет привязки атрибута 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;
Согласно этому коду
- Angularjs регистрирует $ Наблюдатель для атрибута (evalAsync, таким образом, он будет выполнен после завершения цепочки кода)
- Значение правильно передается из атрибута, и поэтому мы увидим его значение в функции связывания
- Функция связывания распространяется со значением атрибута.
- Функция связывания меняет значение пропа и завершает свою работу
- Выполнение возвращается к функции $ наблюдателя (потому что она должна выполняться хотя бы один раз)
- $ Наблюдатель выполняется, и он меняет значение обратно на значение атрибута
В результате мы можем сказать, что использование строковых параметров в теле директивы допускается только как значение только для чтения, пока оно не будет заключено в блок тайм-аута (или любое другое с отложенным выполнением)
Незначительные изменения дают одинаковые результаты с обоими префиксами = и @
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>
Причина, по которой директива 'dIsolatedWorks' работала так, как вы ожидаете, заключается в том, что для нее была настроена двусторонняя привязка ('='), но в родительской области действия с именем "attribute" не было переменной. Поэтому директива dIsolatedWorks инициировала переменную.