I'm trying to call parent controller's function, which has not much to do with the directive, when directive's bind value has changed.
I've been looking through the Q&A in stack, but all of them are related to passing a value from directive to controller, which is not my case.
I thought my case was generally common, the scenario is that: display complex objects in a loop, one of property of object bind on a directive. and when the property has changed, do-something with the updated complex object.
However in my code, it prints the old object value instead of updated one. My guess is that my update function is called before $digest process has completed.
any suggestions?
plunker example: https://plnkr.co/edit/bWGxEmJjNmiKCkRZTqOp?p=preview
here is the Controller code:
var $ctrl = this;
$ctrl.items = [
{id: 1, value: 10}, {id: 2, value: 20}, {id: 3, value: 30}
];
$ctrl.update = function(item){
//trying to update item after changing
console.log("updated item is: " + angular.toJson(item));
};
Here is the directive code:
var controller = function($scope){
var $ctrl = this;
$ctrl.clicked = function(){
$ctrl.value = $ctrl.value + 1;
//calling the bind on-change function defined in controller
$ctrl.onChange();
}
};
return {
restrict: 'E',
scope: {
value: '=',
onChange: '&'
},
controller: controller,
controllerAs: '$ctrl',
bindToController: true,
templateUrl: 'directive.html'
};
and Html looks like this:
<div ng-repeat="item in mc.items">
<my-directive value="item.value" on-change="mc.update(item)"></my-directive>
</div>
and directive template:
<button type="button" ng-click="$ctrl.clicked()">{{$ctrl.value}}</button>
You are correct that the update function is called before $digest
process has completed.
One approach is to update the value with ng-model
and ng-change
:
<my-directive ng-model="item.value" ng-change="mc.update(item)">
</my-directive>
JS:
$ctrl.value++;
$ctrl.ngModelCtrl.$setViewValue($ctrl.value);
With this approach, the ngModelController will update the value before calling ng-change.
angular.module('myApp', [])
.controller('myController', function(){
var $ctrl = this;
$ctrl.items = [
{id: 1, value: 10}, {id: 2, value: 20}, {id: 3, value: 30}
];
$ctrl.update = function(item){
//trying to update item after changing, but here it prints out old item instead of updated item.
console.log("updated item is: " + angular.toJson(item));
};
})
.directive('myDirective', function(){
var controller = function(){
var $ctrl = this;
$ctrl.clicked = function(){
$ctrl.value++;
$ctrl.ngModelCtrl.$setViewValue($ctrl.value);
console.log("calling clicked in directive and value is ", $ctrl.value);
}
};
return {
restrict: 'E',
require: {ngModelCtrl: 'ngModel'},
scope: {
value: '<ngModel',
},
controller: controller,
controllerAs: '$ctrl',
bindToController: true,
template: `<button type="button" ng-click="$ctrl.clicked()">
{{$ctrl.value}}
</button>`
};
});
<script src="//unpkg.com/angular@1.6/angular.js"></script>
<body ng-app='myApp' ng-controller="myController as mc">
<div ng-repeat="item in mc.items">
id={{item.id}}
<my-directive ng-model="item.value" ng-change="mc.update(item)">
</my-directive>
</div>
</body>
I don't quite understand those two lines:
require: {ngModelCtrl: 'ngModel'}
. does ngModelCtrl works as renaming 'ngModel' so that it can be used in directive's controller?value: '<ngModel'
. what does'<'
do?
require: {ngModelCtrl: 'ngModel'}
binds the ng-model
controller API to the directive controller with the name ngModelCtrl
.
scope: {value: '<ngModel'}
creates a one-way binding of the ng-model
attribute to the controller with the name value
.
For more information, see
Using ng-model
enables integration with the validation API of the ngFormController. One can create custom form components with multiple inputs.
For more information, see