У меня есть директива, которая имеет 2 атрибута:
1. объект заголовка, переданный от контроллера.
2. Функция обмена, переданная с контроллера.
scope: {
title: '=',
change: '&'
}
//on the link function I update the object, and call the function.
link: function(scope) {
scope.setValue = function() {
scope.title = "Yaniv"
scope.change();
};
},
так или иначе, хотя я написал это противоположным образом, кажется, что сначала он вызывает функцию, и только тогда он обновляет заголовок. Каков наилучший способ преодолеть это? Я уже думал об использовании setTimeout, и он действительно работал над этим. но, интересно, почему эта проблема произошла, и есть ли здесь более чистое решение. прикрепленный скрипт JS: http://jsfiddle.net/sz82r7pg/
Первое, что нужно отметить, это то, что директива имеет свой собственный объект области выделения, из которых атрибут title привязан к заголовку области управления. Эта привязка данных в основном выполняется с помощью часов, и вы можете знать, что обнаружение изменений с использованием часов происходит не мгновенно, происходит внутри цикла дайджеста, что всегда происходит после внесения изменений, а стек вызовов вызывается (в следующей задаче микро/макрос Я точно не знаю, что, но не имеет значения здесь). Однако вызов функции происходит мгновенно. Итак, что происходит, это следующее:
Это вполне ожидаемое поведение. Самый простой способ в вашем случае - не использовать свое собственное обнаружение изменений, но использовать встроенный в угловой:
angular.module('zippyModule', [])
.controller("Ctrl3", function ($scope) {
$scope.title = 'Ori';
$scope.$watch("title", function(newValue, oldValue) {
if (newValue !== oldValue) {
alert(newValue);
}
});
})
.directive('zippy', function() {
return {
restrict: 'AE',
scope: {
title:'=zTitle'
},
template: '<button ng-click="setValue()">What would be the value of title??</button>',
link: function(scope) {
scope.setValue = function () {
scope.title = "Yaniv";
};
}
}
});
button {
font-size:24px;
margin:40px;
padding: 10px 40px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.js"></script>
<div ng-app="zippyModule">
<div ng-controller="Ctrl3">
<div zippy z-title="title"></div>
</div>
</div>
При написании этого фрагмента я понял, что вы используете древнюю версию angularjs в скрипке (1.0.2). Мне пришлось сделать небольшую модификацию для работы с 1.5.x.
Если вы не хотите использовать часы, то лучшее, что вы можете сделать, это просто передать новый заголовок функции изменения.
angular.module('zippyModule', [])
.controller("Ctrl3", function ($scope) {
$scope.title = 'Ori';
$scope.foo = function(newTitle) {
alert(newTitle);
};
})
.directive('zippy', function() {
return {
restrict: 'AE',
scope: {
change: '&'
},
template: '<button ng-click="setValue()">What would be the value of title??</button>',
link: function(scope) {
scope.setValue = function () {
scope.change({title:"Yaniv"});
};
}
}
});
button {
font-size:24px;
margin:40px;
padding: 10px 40px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.js"></script>
<div ng-app="zippyModule">
<div ng-controller="Ctrl3">
<div zippy change="foo(title)"></div>
</div>
</div>
ОБНОВИТЬ
Оказалось, что в комментариях вы хотите сделать несколько более жесткую связь между контроллером и директивой. Такая вещь обычно считается плохим дизайном, но бывают случаи, когда это единственное правильное решение (чаще всего задействуются неглавные компоненты). Поэтому идея состоит в том, чтобы создать объект API, который можно напрямую манипулировать, и передать его в директиву.
angular.module('zippyModule', [])
.controller("Ctrl3", function ($scope) {
$scope.title = 'Ori';
$scope.fooApiImpl = {
title: "Ori",
change: function() {
alert($scope.fooApiImpl.title);
}
};
})
.directive('zippy', function() {
return {
restrict: 'AE',
scope: {
fooApi: '='
},
template: '<button ng-click="setValue()">What would be the value of title??</button>',
link: function(scope) {
scope.setValue = function () {
scope.fooApi.title = "Yaniv";
scope.fooApi.change();
};
}
}
});
button {
font-size:24px;
margin:40px;
padding: 10px 40px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.js"></script>
<div ng-app="zippyModule">
<div ng-controller="Ctrl3">
<div zippy foo-api="fooApiImpl"></div>
</div>
</div>
title
двусторонняя привязка обновляется в родительской области в конце дайджеста. До тех пор изменение значения title
не распространяется из области действия в родительскую область.
setValue
вызывается ng-click
и запускается во время дайджеста. Это означает, что change
следует вызывать после текущего дайджеста с помощью setTimeout
или $imeout
:
scope.setValue = function () {
scope.title = "Yaniv"
$imeout(() => scope.change());
};
Что указывает на плохой запах и проблему XY, потому что обновление title
уже привязано к перевариванию, а change
избыточно. Это работа для рамки. изменения title
следует отслеживать с помощью
$scope.$watch('title', (newValue, oldValue) => {
if (newValue === oldValue) return;
...
});
в родительской области.
change: '&'
, новое значение может быть передано с помощью scope.change(val)
, `title: '='` является избыточным и наоборот. В основном это либо тот, либо другой. Есть ли причина вашего решения? Потому что $scope.$watch
- идиоматическое, более чистое решение .