How to run Controller first before Angularjs directive?
Could help me in giving an example or documentation of how to render the entire controller first before a custom directive is executed.
What I have in the controller is a value: $scope.total = 200;
In the HTML I have the following
<div val-Custom><ul><li data-value="{{total}}"></li></ul></div>
Now I want to catch that value in my ejem directive:
ctrlsaldosyconsumos.directive('valCustom', function() {
return function(scope, element, attrs) {
//aqui hago otras cosas me interesa mas
attrs.$observe('valCustom', function() {
element.find('li').animate({ width: element.attr("data-value") + '%' }, 350);
});
}
})
Now that data-value in the directive comes out to me undefined
and if I put it, for example
<li data-value="200"></li>
This does execute correctly. I think the directive is running first without having loaded the controller value ($scope.total
).
Any suggestions or help I will thank you, I am starting on this from AngularJS (Angular 1) and more in directives. Thank you.
3 answers
Short answer:
The controller always runs first before the{[11 directive]}
Long answer:
First of all remember that ng-controller
is a directive as well. The order of execution of directives is as follows
compile padre
compile hijo
controller padre => ng-controller
pre-link padre
controller hijo => tu directiva
pre-link hijo
post-link hijo
post-link padre
You can check it in the following snippet
angular.module('app', [])
.directive('padre', function() {
return {
restrict: 'E',
compile: function() {
console.log('Compile padre');
return {
pre: function() {
console.log('Pre padre');
},
post: function() {
console.log('Post padre');
}
};
},
controller: function() {
console.log('Controller padre');
}
};
})
.directive('hijo', function() {
return {
restrict: 'E',
compile: function() {
console.log('Compile hijo');
return {
pre: function() {
console.log('Pre hijo');
},
post: function() {
console.log('Post hijo');
}
};
},
controller: function() {
console.log('Controller hijo');
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<padre>
<hijo></hijo>
</padre>
</div>
Which means that if your directive is in the DOM inside your controller it will never execute first of all.
If your code depends on Ajax calls, it doesn't matter in the order you execute it, your directive is likely to reach Phase post-link
and the results haven't arrived yet via ajax.
The solution could be to use ng-if
to signal when the directive can be rendered.
angular.module('app', [])
.controller('UtilCtrl', function($scope, $timeout) {
$scope.muestraHijo = false;
$timeout(function() {
$scope.muestraHijo = true;
}, 1000)
})
.directive('padre', function() {
return {
restrict: 'E',
compile: function() {
console.log('Compile padre');
return {
pre: function() {
console.log('Pre padre');
},
post: function() {
console.log('Post padre');
}
};
},
controller: function() {
console.log('Controller padre');
}
};
})
.directive('hijo', function() {
return {
restrict: 'E',
compile: function() {
console.log('Compile hijo');
return {
pre: function() {
console.log('Pre hijo');
},
post: function() {
console.log('Post hijo');
}
};
},
controller: function() {
console.log('Controller hijo');
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="UtilCtrl">
<padre>
<div ng-if="muestraHijo">
<hijo></hijo>
</div>
</padre>
</div>
Lee https://github.com/angular/angular.js/wiki/Understanding-Directives
If you need to wait for
$scope
data has finished loading try usingng-if
to delay processing of a DOM block.
Similar problem, I solved it by considering $watch Inside My directive controller, in this case it was a collection type attribute:
$scope.$watchCollection("datos", function (newValue, oldValue) {
if (newValue === oldValue) {
return;
}
if ($scope.datos != undefined)
loadGraphEChart($scope.labels, $scope.datos, $scope.titulo, $scope.idgraph);
});
With the above, I managed to get the loadGraphEChart to run once
$scope.datos != undefined
Note: the data value was not assigned given some user event, but was fed as a policy attribute given the response to an http request
<div echart-graph ng-model="edades"
idgraph="Edades"
stilo="height:350px;width:98%;"
titulo="Edades"
labels="edades.labels"
datos="edades.datos"></div>
Maybe this can guide you, I solve it like this:
<div val-Custom algo="$scope.algo">
<ul>
<li data-value="{{total}}"></li>
</ul>
</div>
In your directive indicate the following:
ctrlsaldosyconsumos.directive('valCustom', function() {
return {
restrict: 'A',
scope: {
algo: '=algo'
},
link: function(scope, elem, attr){
console.log("llamando al scope.algo deberias tener disponible tus datos")
attrs.$observe('valCustom', function() {
element.find('li').animate({ width: element.attr("data-value") + '%' }, 350);
});
}
}
})
This might help you understand how it works:
Documentary AngularJS (Angular 1)
Navigate to the part that says: Isolating the Scope of a Directive
Greetings, I hope to help or guide you.