web-dev-qa-db-fra.com

Exécuter du code après qu'une animation AngularJS est terminée

J'ai un élément dont la visibilité est basculée par ng-show. J'utilise également des animations CSS - celles automatiques de ng-animate - sur cet élément pour animer son entrée.

L'élément contiendra soit une image ou une vidéo. 

Dans le cas où l'élément contient une vidéo, je souhaite la lire, mais je ne souhaite pas la lire tant que l'animation n'est pas terminée.

En tant que tel, je me demandais s’il existait un moyen simple de lier un rappel à la fin d’une animation CSS dans AngularJS?

Les docs font référence à doneCallback, mais je ne vois pas comment le spécifier.

Une solution de contournement (?) À laquelle j'ai pensé est $watching element.hasClass("ng-hide-add-active") et d'attendre qu'il soit déclenché avec (true, false), ce qui implique qu'il a été simplement supprimé. 

Y a-t-il un moyen plus agréable?

25
Ed Hinchliffe

@ michael-charemza answer a bien fonctionné pour moi. Si vous utilisez Angular 1.3, ils ont légèrement modifié la promesse. Je suis resté coincé là-dessus un petit peu, mais voici le changement qui a permis de le mettre en place:

if (show) {
  $animate.removeClass(element, 'ng-hide').then(scope.afterShow);
}
if (!show) {
  $animate.addClass(element, 'ng-hide').then(scope.afterHide);
}

Plunker: Exemple de code

26
Lereveme

Comme @zeroflagL l'a suggéré, une directive personnalisée pour remplacer ngShow est probablement la solution. Vous pouvez utiliser & pour passer des rappels dans la directive, qui peut être appelée une fois les animations terminées. Pour des raisons de cohérence, les animations sont réalisées en ajoutant et en supprimant la classe ng-hide, qui est la même méthode que celle utilisée par la directive habituelle ngShow:

app.directive('myShow', function($animate) {
  return {
    scope: {
      'myShow': '=',
      'afterShow': '&',
      'afterHide': '&'
    },
    link: function(scope, element) {
      scope.$watch('myShow', function(show, oldShow) {
        if (show) {
          $animate.removeClass(element, 'ng-hide', scope.afterShow);
        }
        if (!show) {
          $animate.addClass(element, 'ng-hide', scope.afterHide);
        }
      });
    }
  }
})

Exemple d'utilisation de cette écoute d'une variable de portée show serait:

<div my-show="show" after-hide="afterHide()" after-show="afterShow()">...</div>

Comme il s’agit d’ajouter/de supprimer la classe ng-hide, les points concernant l’animation des documents relatifs à ngShow sont toujours valables et vous devez ajouter display: block !important au CSS.

Vous pouvez voir un exemple de cela en action sur ce Plunker .

26
Michal Charemza

La solution @ michal-charemza fonctionne très bien, mais la directive crée une portée isolée. Par conséquent, dans certains cas, elle ne peut pas remplacer directement la directive par défaut ng-show. 

Je l'ai un peu modifié pour qu'il ne crée pas de nouvelles portées et puisse être utilisé de manière interchangeable avec la directive ng-show.

app.directive('myShow', function($animate) {
  return {
    link: function(scope, element, attrs) {
      scope.$watch(attrs['myShow'], function(show, oldShow) {
        if (show) {
          $animate.removeClass(element, 'ng-hide').then(function(){
            scope.$apply(attrs['myAfterShow']);
          });
        } else {
          $animate.addClass(element, 'ng-hide').then(function(){
            scope.$apply(attrs['myAfterHide']);
          });
        }
      });
    }
  }
})

Usage:

<div my-show="show" my-after-hide="afterHide()" my-after-show="afterShow()">...</div>

Plunker

1
m.bemowski