Reputation: 3734
In an AngularJS application I have a parent directive and a child directive.
angular
.module('myApp')
.directive('customForm', function(customService, apiV1, Constants, $timeout) {
return {
restrict: 'E',
scope: {
param1: '=',
param2: '=?',
boolean1: '@?'
},
template,
link: function(scope, parentController) {
scope.data = customService.newClient;
//some stuff...
angular
.module('myApp')
.directive('customToolForm', function () {
return {
restrict: 'E',
scope: {
name: '=',
city: '=',
postalCode: '='
},
template,
controller: function ($scope, $rootScope, Constants, apiV1, customService) {
$scope.doSomethingWithPostalCode = function() {
$scope.$parent.doSomethingWithPostalCode();
}
//some stuff...
<address-client-creation name="data.client.name" city="data.client.city"
postal-code="data.client.postalCode">
</address-client-creation>
<input maxlength="5" type="text" data-ng-model="postalCode"
data-ng-change="doSomethingWithPostalCode();">
The issue I have is that :
When the method doSomethingWithPostalCode
is triggered from the childDirective, the value of the postalCode in the child is not the same as the client.postalCode of the parent, but at the end of the method it is.
it seems that the two way binding event that update the parent value is happening after the function call
So my question is what is the best way to ensure that the $parent scope is updated before calling the method?
Upvotes: 1
Views: 606
Reputation: 48948
The AngularJS framework implements two-way ('='
) binding by adding a watcher to the child scope which transfer the data from the child scope to the parent scope. The watcher requires a digest cycle to detect the change and do the transfer.
A more modern approach is to use one-way ("<"
) binding for inputs and expression ("&"
) binding for outputs:
app.directive('customToolForm', function () {
return {
restrict: 'E',
scope: {
name: '<',
city: '<',
̶p̶o̶s̶t̶a̶l̶C̶o̶d̶e̶:̶ ̶'̶=̶'̶
postalCode: '<',
postalCodeChange: '&',
},
template: `
<input maxlength="5" type="text" data-ng-model="postalCode"
data-ng-change="doSomethingWithPostalCode(postalCode);">
`,
controller: function ($scope, $rootScope, Constants, apiV1, customService) {
$scope.doSomethingWithPostalCode = function(postalCode) {
̶$̶s̶c̶o̶p̶e̶.̶$̶p̶a̶r̶e̶n̶t̶.̶d̶o̶S̶o̶m̶e̶t̶h̶i̶n̶g̶W̶i̶t̶h̶P̶o̶s̶t̶a̶l̶C̶o̶d̶e̶(̶)̶;̶
$scope.postalCodeChange({$event: postalCode});
}
//some stuff...
Usage:
<custom-form-tool
name="data.client.name" city="data.client.city"
postal-code="data.client.postalCode"
postal-code-change="data.client.postalCode=$event; doSomething($event)"
>
</custom-form-tool>
Using expression ("&"
) binding immediately makes the event data available to the parent controller.
It also makes the migration path to Angular 2+ easier.
For more information, see
Upvotes: 2
Reputation: 3734
A solution I found was to use $watch
in the childDirective:
/**
* Using $watch instead of data-ng-change ensure that bindings are updated
*/
$scope.$watch('postalCode', function() {
$scope.$parent.doSomethingWithPostalCode();
});
And so removing the data-ng-change
on the input of the child directive :
<input maxlength="5" type="text" data-ng-model="postalCode">
When debugging inside the $watch method, I could verify that the parent $scope was already updated.
Not sure if it is a real solution or more like a hack.
Upvotes: 0