Is the angular scope binding &(ampersand) a one time binding? I see it referred to as a one-way binding, but is it also one-time?
Let's say I have:
<my-custom-directive data-item="item" />
And my directive is declared as follows:
.directive('myCustomDirective', [
'$log', function ($log) {
return {
restrict: 'E',
templateUrl: '/template.html',
scope: {
dataItem: '&'
}
controller: function ($scope) {
// ....
}
}])
The reason I'm asking if the binding is one-time is because that seems to be what I'm observing, that is. If item
in the parent scope is updated, the one in the directive is not updated.
Am I right in saying that the binding is one time?
To achieve what I want, where the directive keeps a copy without affecting the parent scope's item -- I did this:
.directive('myCustomDirective', [
'$log', function ($log) {
return {
restrict: 'E',
templateUrl: '/template.html',
scope: {
dataItemOriginal: '='
},
link: function ($scope) {
$scope.$watch('dataItemOriginal', function () {
$scope.dataItem = window.angular.copy($scope.dataItemOriginal);
});
},
controller: function ($scope) {
//....
}
}])
Is this proper or is there a better way?
There is a better way. Your current solution is setting up three watches - two are created by using the "=" binding, and then the extra $watch you create to make a copy. $watches are relatively expensive.
Here is an alternative that doesn't create any watches:
.directive('myCustomDirective', [
'$log', function ($log) {
return {
restrict: 'E',
templateUrl: '<div ng-click="clicked()">Click me for current value</div>',
scope: {
item: '&'
},
controller: function($scope) {
$scope.clicked = function(){
alert(item()); //item() returns current value of parent's $scope.item property
}
$scope.val = item(); //val is the initial value of $parent.item
$scope.val = 42; //$parent.item is unaffected.
}
}])
& is highly misunderstood. While it can be used for passing functions into an isolated scope, what it actually does is:
provides a way to execute an expression in the context of the parent scope
It generates a function in the directive that, when called, executes the expression in the context of the parent scope. The expression does not have to be a function or function call. It can be any valid angular expression.
So in your example:
<my-custom-directive data-item="item"></my-custom-directive>
scope: {
item: '&'
}
$scope.item in the directive will be a function that you can call in the controller or in your template. Invoking that function will return the object referenced by "item" in your parent scope. There is no binding with & - no watches are used.
Where the "one-way-binding" misnomer comes in is that using &, the directive cannot change the value of $parent.item, where as when using "=", the directive, by virtue of the $watches created, can. It is also not "one time", either, since it's not technically bound at all.
Since the mechanism that angular uses to generate the function involves $parse, it is possible for the directive to pass in "locals" that override values in the expression with values from the directive. So, in the directive controller, if you did:
item({item: 42})
it would always return 42, regardless of the value of item in the parent scope. It is this feature that makes & useful for executing function expressions on the parent scope with data from the directive.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With