web-dev-qa-db-fra.com

angular - ng-if - comment rappeler après que le template ng-if ait été rendu

dans Angular, je dois appeler une fonction après le chargement d'un élément de classe. L'affichage de l'élément est contrôlé via ng-if = 'expr'. La valeur de $ scope.expr est définie après la réponse d'un appel ajax. 

Maintenant, si j'essaie de mettre $ watch sur expr, ou d'utiliser $ evalAsync. ça ne marche pas. la raison en est probablement que ces événements sont exécutés avant que la partie modèle ne soit réellement exécutée.

Voici un exemple de code: http://jsbin.com/kuyas/1/edit Il me faut ici un type de rappel sur ng -si celui-ci est exécuté après le rendu du modèle.

16
Charanjeet Kaur

Le problème était qu’il n’y avait aucun moyen de savoir si angulaire était fait avec la boucle de digestion, en s’assurant que tous les éléments avaient été restitués.

Pour résoudre ce problème, il y avait deux options

  1. Enveloppez votre fonction de rappel dans une directive. inclure cette directive dans ng-if. et rendez cette expression vraie uniquement lorsque vous voulez que votre rappel soit exécuté.
  2. Appelez votre fonction de rappel à l'intérieur, setTimeOut(function(){ ... }, 0);, en tant que navigateur par défaut, conservez tous les événements dans une file d'attente. Par conséquent, lorsque la boucle de digestion est en cours d'exécution, votre fonction de rappel entre dans la file d'attente et est exécutée dès que la boucle de digestion est terminée.
16
Charanjeet Kaur

Une solution possible serait de créer une directive qui fasse tout ce que vous voulez. Si vous utilisez ensuite cette directive uniquement dans la section HTML contrôlée par le ng-if, elle sera inactive jusqu'à ce que l'expression ng-if soit vraie.

Est-ce que ça ferait ce que tu veux?

26
John Munsch

La solution la plus simple à mon avis est de procéder comme suit:

<div ng-if="sectionActivated">
    <div ng-init="callBack()"></div>
</div>

Votre rappel ne sera appelé que lorsque ce qui est affecté par ng-if a été rendu.

2
aBertrand

La directive pourrait ressembler à ceci:

import * as angular from 'angular';

class OnFinishRenderDirective implements angular.IDirective {

  public restrict = 'A';
  public replace = false;

  public link = (
    scope: any,
    // scope:        angular.IScope,
    element: angular.IAugmentedJQuery,
    attr: any,
    modelCtrl: any,
    link: angular.ITemplateLinkingFunction ) => {

    if ( scope.$last === true ) {
      this.$timeout(() => {
        scope.$emit( 'elementRendered' );
      } );
    }

  }

  constructor( private $timeout: angular.ITimeoutService ) { }

}

export function onFinishRenderFactory(): angular.IDirectiveFactory {

  var directive = ( $timeout: angular.ITimeoutService ) => new OnFinishRenderDirective( $timeout );
  directive.$inject = [ '$timeout' ];
  return directive;
}

Il faudrait l'importer et l'ajouter à votre module

import { onFinishRenderFactory } from './onFinishRender/onFinishRender.directive';

angular.module( 'yourModule', [] )
.directive( 'onFinishRender', onFinishRenderFactory() )

Vous pouvez ensuite utiliser la directive quelque part dans votre balisage pour émettre l'événement une fois la directive rendue.

<div onFinishRender>I am rendered</div>

Vous pouvez même ajouter un attribut supplémentaire dans la directive DIV que vous pouvez ensuite extraire de l'objet ATTR dans la fonction link et l'ajouter à votre fonction $ emit pour identifier cette DIV spécifique à restituer.

Est-ce que ça répond à votre question? 

1
Mattijs