J'ai une directive auto-carousel
Qui itère à travers les éléments liés children.
Cependant, les enfants ne sont pas encore chargés dans le DOM, car leurs expressions ng-if
N'ont pas encore été analysées.
Comment puis-je m'assurer que la directive parent sait qu'il y a eu des changements dans son arborescence DOM?
<ul class="unstyled" auto-carousel>
<li class="slide" ng-if="name">{{name}}</li>
...
<li class="slide" ng-if="email">{{email}}</li>
</ul>
Je pourrais utiliser $timeout
Mais cela semble peu fiable. Je pourrais également utiliser ng-show
Au lieu de ng-if
Mais cela ne répond pas à la question et pas à ce dont j'ai besoin.
Voici donc ce que j'ai fini par faire:
J'ai découvert que vous pouviez transmettre une fonction à $scope.$watch
. À partir de là, il est assez simple de renvoyer la valeur de l'expression que vous souhaitez surveiller pour les modifications. Cela fonctionnera exactement comme passer une chaîne de clé pour une propriété sur la portée.
link: function ($scope, $el, $attrs) {
$scope.$watch(
function () { return $el[0].childNodes.length; },
function (newValue, oldValue) {
if (newValue !== oldValue) {
// code goes here
}
}
);
}
Je regarde childNodes
, pas children
, car la liste childNodes
contient des éléments ainsi que nœuds de texte et commentaires. Cela n'a pas de prix car Angular utilise des espaces réservés de commentaire pour des directives comme ng-repeat
, ng-if
, ng-switch
et ng-include
qui effectue la transclusion et modifie le DOM, tandis que children
ne contient que des éléments.
Si vous devez surveiller les changements plus profonds dans le dom de l'élément, MutationObserver est le chemin à parcourir:
.directive('myDirective', function() {
return {
...
link: function(scope, element, attrs) {
var observer = new MutationObserver(function(mutations) {
// your code here ...
});
observer.observe(element[0], {
childList: true,
subtree: true
});
}
};
});
J'ai créé un module de directive pour cela angular-dom-events
Dans votre cas, vous pourriez
<ul class="unstyled" auto-carousel>
<li class="slide" ng-if="name" dom-on-create="nameCreated()">{{name}}</li>
<li class="slide" ng-if="email" dom-on-destroy="emailDestroyed()">{{email}}</li>
</ul>
Actuellement, ne prend en charge que dom-on-create
et dom-on-destroy
, mais a de meilleures performances que la réponse acceptée car elle ne se déclenchera qu'une seule fois pour chaque événement dom, plutôt que de vérifier à plusieurs reprises le rappel $ watch.
Bien que je ne pense pas que ce soit avec les recommandations d'angular, vous pouvez utiliser ng-init qui se déclenche lors de l'initialisation de l'élément:
<ul class="unstyled" auto-carousel>
<li class="slide" ng-if="name" ng-init="recheck()">{{name}}</li>
<li class="slide" ng-if="email" ng-init="recheck()">{{email}}</li>
</ul>
Vous pouvez essayer de compiler le contenu de la directive d'abord dans votre fonction de lien. Par exemple:
angular.module('myApp').directive('autoCarousel', ['$compile', function ($compile) {
return {
templateUrl: 'views/auto-carousel.html',
restrict: 'A',
replace: true,
link: function (scope, element, attr) {
$compile(element.contents())(scope);
// your code goes here
}
}
}]);