In my directive, I have a controller variable, page which gets incremented when you press the button in the directive. However, the next line, scope.alertPage()
The reason why it does not show the updated value immediately is because the 2 way binding updates the parent (or the consumer scope of the directive) scope's bound value only during the digest cycle. Digest cycle happens after the ng-click is triggered. And hence $scope.page
in the controller is not yet updated. You can get around this in many ways by using a timeout
which will defer the action to run at the end of the digest cycle. You could also do it by setting an object which holds the value as 2-way bound property. Since 2-way bound property and parent scope share the same object reference you will see the change immediately.
Method 1 - using a timeout:
scope.incrementPage = function() {
scope.page += 1;
$timeout(scope.alertPage)
}
Method 2 - Bind an object:
//In your controller
$scope.page2 = {value:1};
//In your directive
scope.incrementPage = function() {
scope.page.value += 1;
scope.alertPage();
}
Method3 - Pass the value using function binding with argument:
//In your controller
$scope.alertPage = function(val) {
alert(val);
}
and
<!--In the view-->
<div incrementer page="page" alert-page="alertPage(page)"></div>
and
//In the directive
scope.incrementPage = function() {
scope.page += 1;
scope.alertPage({page:scope.page});
}
app = angular.module('app', []);
app.controller('myCtrl', function($scope) {
$scope.page = 1;
$scope.page2 = {value:1};
$scope.alertPage = function() {
alert($scope.page);
}
$scope.alertPage2 = function() {
alert($scope.page2.value);
}
})
app.directive('incrementer', function($timeout) {
return {
scope: {
page: '=',
alertPage: '&',
page2:"=",
alertPage2: '&'
},
template: '<button ng-click="incrementPage()">increment page</button>',
link: function(scope, elem, attrs) {
scope.incrementPage = function() {
scope.page += 1;
scope.page2.value += 1;
$timeout(function(){ scope.alertPage() });
scope.alertPage2();
}
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<div incrementer page="page" alert-page="alertPage()" page2="page2" alert-page2="alertPage2()"></div>
</div>
You can pass the variable by reference, then the update will be immediate (because you wont copy it, but simply pass its location in memory).
View:
<incrementer page="data" alert-page='alertPage()'></incrementer>
Directive:
link: function(scope, elem, attrs) {
scope.incrementPage = function() {
scope.page.page += 1;
scope.alertPage();
}
Try doing this slightly differently. Pass in a function to do the increment rather than incrementing inside the directive
HTML
<incrementer page='incPage()' alert-page='alertPage()'></incrementer>
Controller
$scope.incPage = function() { // Function to increment
$scope.page++;
};
In Directive
scope: {
page: '&', // Receive like this
alertPage: '&'
},
link: function(scope, elem, attrs) {
scope.incrementPage = function() {
scope.page(); // Call as function
scope.alertPage();
}
}
The problem is that the timeline is off.
To get around this, you need to either call the alert function after the digest cycle (e.g. $timeout
) or you need to watch for changes in the parent scope.
// in controller
$scope.$watch('page', function (currentValue, previousValue) {
// initially triggered with same value
if (currentValue > previousValue) {
alert(currentValue)
}
})
Then change the value naturally.
// in directive html
<button ng-click="page = page + 1">