Angular.js: ng-show / hide est retardé sur un élément en cours d'animation

Créé le 16 juil. 2014  ·  17Commentaires  ·  Source: angular/angular.js

Ce n'est pas un comportement attendu si vous effectuez une animation constante sur quelque chose comme un spinner de chargement et que vous souhaitez simplement le masquer ou l'afficher immédiatement.

L'élément n'a pas été dit être géré par ng-animate, je veux juste que ng-show / hide normal se produise instantanément, et toutes les animations css qui sont en cours ne devraient pas être pertinentes, je pense.

Violon: http://jsfiddle.net/PvS8k/2/

Décochez "show loader" et notez que cela prend quelques secondes pour disparaître.

Je pense que c'est un changement récent car notre chargeur ne restait pas dans notre application avant la mise à niveau. Je pense que nous étions sur 1.12 avant.

Je dois manquer quelque chose dans ma compréhension de la façon d'utiliser / ne pas utiliser ng-animate, non? Dans ce cas, je ne veux pas l'utiliser, mais si je peux l'utiliser pour ignorer cet élément, cela fonctionnerait aussi. Un comportement vraiment surprenant.

ngAnimate broken expected use bug

Commentaire le plus utile

@ tole42 Voici la solution de contournement:

.YourElementClass.ng-animate { -webkit-animation: none 0s; }

Tous les 17 commentaires

ngAnimate est gourmand car il suppose que toutes les images clés / code de transition qui sont actifs sur l'élément pendant l'un des déclencheurs sont là pour être animés via ngAnimate. Par conséquent, dans ce cas, bien que .loader n'ait rien à voir avec ngShow / ngHide, il est toujours considéré comme une animation valide.

Pour contourner ce problème, effacez simplement le style de l'animation lorsque la classe .ng-animate est appliquée à l'élément.

http://jsfiddle.net/PvS8k/4/

C'est un problème avec l'héritage CSS. S'il y avait un meilleur moyen de détecter les styles sans avoir à se fier uniquement à getComputedStyle, alors ce genre de bizarreries pourrait éventuellement être évité.

@matsko Je pense que ce cas particulier est en fait une régression. Comme vous pouvez le voir dans le plunker de @SimpleAsCouldBe, ou dans ce plunker http://plnkr.co/edit/5cfIXfNryNOzK66q9YWL?p=preview , en 1.2.17, l'élément ne disparaît pas immédiatement, mais en 1.2.16, il Est-ce que. Cela est probablement dû à https://github.com/angular/angular.js/commit/55b2f0e8620465559016b424967d90a86af597c0
Je pense que cela mérite une inspection un peu plus approfondie; au moins, il devrait y avoir une note dans le journal des modifications et la documentation à ce sujet.

Merci pour la solution de contournement, il fait l'affaire comme prévu.

Deux points. L'un est spécifique à ng-show et l'autre est général.

ng-show + animations infinies:

Une animation infinie devrait-elle vraiment retarder le masquage d'un ng-show ? J'ai essayé de compter les secondes et ce n'est pas toujours 4 secondes qu'il attend pour le cacher. Parfois, ses 5 ou 7 ... semblent varier. De plus, si vous activez et désactivez la case à cocher, elle ne se cache jamais. Je pense qu'il y a un bug qui se cache ici quelque part.

Philisophique

En tant que non-contributeur, je n'ai pas grand-chose à dire, mais peut-être que la désactivation n'est pas la bonne stratégie pour cette bibliothèque. C'est tellement magique d'avoir une bibliothèque JS qui réagit aux règles CSS. Si je devais marquer des éléments avec ng-animatable je serais beaucoup plus préparé à cela.

@SimpleAsCouldBe oui, j'ai pensé de la même manière qu'il serait peut-être préférable d'exiger que toutes les animations aient un préfixe de classe animate- tel que ngAnimate se connecte ensuite aux animations.

En ce qui concerne le délai, ce n'est pas qu'il y a un délai, c'est que ngAnimate annule la partie infinie et n'exécute l'animation qu'une seule fois. Par conséquent, lorsque vous le masquez, il attend 2 s * 1,5 = 3 secondes, puis il exécute la vérification du délai d'expiration et ferme l'animation. C'est donc une fenêtre de temps inutile qui ne devrait pas du tout être là - seule la détection du style CSS est très limitée.

@Narretz alors que le commit que vous avez fourni peut affecter cet exemple particulier, il n'a en fait rien à voir avec la régression. La raison en est que le style .ng-hide qui existait avant le correctif appliquait la display:none à un moment différent. Mais le correctif actuel l'applique UNIQUEMENT après que toutes les animations sont terminées (une fois que la classe .ng-animate est supprimée).

Jetez un œil à la démo ci-dessous. Voyez comment il existe deux ensembles de sélecteurs pour la classe .blue : un avec .ng-animate et sans. Malgré l'application immédiate de la classe .blue , ngAnimate pense toujours qu'une animation est due et attend 3s (rappelez-vous 2s * 1,5) avant d'appliquer un délai de fermeture. Normalement, ce serait 2s, mais un événement animationend n'est jamais déclenché car l'animation réelle sur l'élément (qui est là à cause de .loader ) est infinie et n'est pas déclenchée par ng-class ( ou ng-show pour l'exemple précédent). Cela étant dit, cela n'est pas effectué en raison de la correction de bogue précédente.
http://jsfiddle.net/PvS8k/15/

Il serait peut-être préférable de rendre ngAnimate moins naïf et de ne s'animer que lorsque animated- est là comme préfixe CSS quelque part.

Je pense que si vous êtes ouvert à un changement radical comme la gestion de l'animation opt-in, cela créerait une expérience de développeur moins surprenante.

Seriez-vous ouvert au préfixe avec quelque chose de spécifique angulaire comme .ng-animate plutôt que simple .animate ?

J'ai le même problème:
Avec angulaire> = 1.2.17 http://jsfiddle.net/9krLr/17/
Avec angulaire 1.2.16, tout va bien: http://jsfiddle.net/EZpQQ/1/

@ tole42 Voici la solution de contournement:

.YourElementClass.ng-animate { -webkit-animation: none 0s; }

Merci de votre aide. La solution de contournement ne fonctionne pas :(
Ce qui est faux?
http://jsfiddle.net/9krLr/21/

@ tole42 Rien dans ce violon

Je crois que je vois le même problème que @ tole42 . Avec ngAnimate include dans un module, la fonctionnalité standard ng-hide / ng-show ne fonctionne pas correctement pour le cas de base lorsque vous n'essayez pas de les animer. En d'autres termes, lorsque vous utilisez ng-hide / ng-show sur un élément simple sans aucune classe d'animation appliquée.

<div ng-hide="hideme">hide me</div>

Si je voulais une animation sur cette peau, je ferais quelque chose comme:

<div ng-hide="hideme" class="myanimation">hide me</div>

Il existe des cas dans une application où vous souhaiterez peut-être animer un show / hide et d'autres instances où vous ne souhaitez pas animer. Dans les cas où vous ne souhaitez pas animer, vous ne décorez pas l'élément affiché / masqué avec une classe d'animation personnalisée. Dans cet exemple, Angular ajoute simplement la classe "ng-hide" à un élément caché.

Si vous n'incluez pas du tout ngAnimate dans votre module, cela fonctionne comme prévu: l'élément disparaît immédiatement. Mais en incluant simplement ngAnimate, vous obtenez le comportement montré dans les deux violons que @ tole42 a postés: il y a un délai avant que l'élément auquel la classe "ng-hide" a été ajoutée disparaisse réellement. Il devrait disparaître immédiatement si vous n'essayez pas d'utiliser des animations dessus.

Quelques solutions de contournement qui semblent fonctionner sont:

.ng-hide-add {
    transition: 0s linear all;
}

Ou alors:

.ng-hide {
    display: none !important;
}

Mais il ne semble pas correct que ceux-ci soient nécessaires dans le cas où vous essayez simplement de cacher quelque chose de manière non animée.

Juste pour faire le suivi de quelques découvertes supplémentaires ...

Essayer de résumer le problème au scénario le plus simple possible - afficher / masquer les divs simples - le problème ne se manifeste pas.

J'ai remarqué dans les violons postés par @ tole42 que le

Ces transitions css semblent être le véritable coupable, car angular-animate en prend les durées. C'est ce qui provoque le retard visuel lors de l'affichage / du masquage de ces éléments, même si vous n'essayez pas intentionnellement d'animer cette transition.

Je ne pense donc pas que ce soit nécessairement un problème qu'Angular devrait tenter de résoudre. C'est plus un effet secondaire de l'utilisation de l'animation angulaire avec d'autres bibliothèques css, qui peuvent avoir des transitions css intégrées auxquelles vous ne vous attendez pas!

Il a fallu beaucoup de temps pour trouver la cause profonde, mais c'était bien de trouver enfin une raison qui ait du sens.

Oui, c'est un problème important avec ngAnimate, mais en raison du manque de contrôle de getComputedStyle et de la cascade de transitions dans d'autres bibliothèques, ngAnimate est incapable de le détecter.

Il existe deux solutions pour résoudre ce problème:

1) Remplacez le style de la classe .ng-animate :
http://jsfiddle.net/9krLr/27/

La raison pour laquelle cela n'a pas fonctionné pour vous auparavant était à cause du manque de spécificité CSS.

2) Utilisez $animateProvider.classNameFilter(regex) . Dans ce cas, l'expression régulière placera un bloc dur sur toutes les animations déclenchées par ngAnimate et autorisera uniquement l'animation à se dérouler si l'expression régulière correspond à un nom de classe présent sur l'élément que vous souhaitez animer.

Oh, mettre la config dans un fournisseur est une bonne façon de procéder, j'aime beaucoup ça, @matsko!

@pnutshellmenace merci pour la solution rapide. Cela m'a sauvé la journée.

Je ne comprends pas quelle était la solution finale ici. @matsko a déclaré:

Il serait peut-être préférable de rendre ngAnimate moins naïf et de n'animer que lorsqu'il est animé - y a-t-il un préfixe CSS quelque part

Mais je ne vois aucune implémentation comme celle-là. J'ai jeté un coup d'œil à $animateProvider.classNameFilter(regex) mais encore une fois, il me reste plus de questions que de réponses. Quelle est la manière pratique de l'implémenter et que se passe-t-il s'il y a plus d'un nom de classe applicable?

Je ne vois aucune raison pour laquelle ngAnimate devrait supposer que je veux tout animer. Il y aura toujours des choses que je ne veux pas animer, et actuellement j'en ai plus que je ne veux pas animer que l'inverse, ce qui rend leur style manuel pour désactiver les transitions peu attrayant.

Edit: J'ai trouvé cette entrée de blog qui met les choses en perspective ... Je vais l'essayer: http://blog.fgribreau.com/2014/03/how-to-configure-ng-animate-to- work-on.html

Edit 2: Ajouter $animateProvider.classNameFilter(/enable-animate/); fonctionné, mais dans le processus, j'ai trouvé un comportement intéressant:

J'avais inclus un fichier .js d'un module angulaire tiers qui avait une dépendance sur ngAnimate, et d'une manière ou d'une autre, cela provoquait le déclenchement d'animations même sur mon propre module. D'une manière ou d'une autre, ngAnimate affectait la portée du module parent?

Je préférerais cette réponse en utilisant $scope.$evalAsync(); pour une opération asynchrone. fonctionne bien.

Cette page vous a été utile?
0 / 5 - 0 notes