Angular.js: ng-show / hide se retrasa en un elemento que se está animando

Creado en 16 jul. 2014  ·  17Comentarios  ·  Fuente: angular/angular.js

Este no es un comportamiento esperado si está haciendo una animación constante en algo como un control giratorio de carga y solo desea ocultarlo o mostrarlo de inmediato.

No se le dijo al elemento que fuera administrado por ng-animate, solo quiero que ng-show / hide normal ocurra instantáneamente, y creo que cualquier animación CSS que esté en curso debería ser irrelevante.

Violín: http://jsfiddle.net/PvS8k/2/

Desmarque "mostrar cargador" y tenga en cuenta que tarda unos segundos en desaparecer.

Creo que este es un cambio reciente porque nuestro cargador no se pegaba a nuestra aplicación antes de actualizar. Creo que estábamos en 1.12 antes.

Debo estar perdiendo algo en mi comprensión de cómo usar / no usar ng-animate, ¿verdad? En este caso, realmente NO quiero usarlo, pero si puedo usarlo para ignorar este elemento, eso también funcionaría. Sin embargo, un comportamiento definitivamente sorprendente.

ngAnimate broken expected use bug

Comentario más útil

@ tole42 Esta es la solución:

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

Todos 17 comentarios

ngAnimate es codicioso ya que asume que todos los fotogramas clave / código de transición que están activos en el elemento durante cualquiera de los disparadores están ahí para ser animados a través de ngAnimate. Por lo tanto, en este caso, a pesar de que .loader no tiene nada que ver con ngShow / ngHide, todavía se selecciona como una animación válida.

Para evitar esto, simplemente borre el estilo de la animación cuando se aplique la clase .ng-animate en el elemento.

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

Este es un problema con la herencia de CSS. Si hubiera una mejor manera de detectar estilos sin tener que depender únicamente de getComputedStyle, entonces este tipo de peculiaridades podrían evitarse.

@matsko Creo que este caso especial es en realidad una regresión. Como puede ver en el plunker de @SimpleAsCouldBe, o en este plunker http://plnkr.co/edit/5cfIXfNryNOzK66q9YWL?p=preview , en 1.2.17, el elemento no desaparece inmediatamente, pero en 1.2.16, lo hace. Es muy probable que esto se deba a https://github.com/angular/angular.js/commit/55b2f0e8620465559016b424967d90a86af597c0
Creo que esto justifica una inspección más cercana; al menos debería haber una nota en el registro de cambios y documentos sobre esto.

Gracias por la solución, funciona como se esperaba.

Dos puntos. Uno es específico de ng-show y el otro es general.

ng-show + animaciones infinitas:

¿Debería una animación infinita _ realmente_ retrasar la ocultación de un ng-show ? Intenté contar los segundos y no siempre son 4 segundos los que espera para ocultarlo. A veces son 5 o 7 ... parece variar. Además, si activa y desactiva la casilla de verificación, nunca se oculta. Creo que hay un error real escondido aquí en alguna parte.

Filosófico

Como no colaborador, no tengo mucho que decir, pero tal vez optar por no participar no sea la estrategia adecuada para esta biblioteca. Es asombrosamente mágico que una biblioteca JS reaccione a las reglas de CSS. Si tuviera que etiquetar elementos con ng-animatable , estaría mucho más preparado para esto.

@SimpleAsCouldBe, sí, he estado pensando lo mismo que tal vez sería mejor requerir que todas las animaciones tengan un prefijo de clase animate- modo que ngAnimate se enganche en las animaciones.

Con respecto al retraso, no es que haya un retraso, es que ngAnimate cancela la porción infinita y solo ejecuta la animación una vez. Por lo tanto, cuando lo oculta, espera 2s * 1.5 = 3 segundos y luego ejecuta la verificación de tiempo de espera y cierra la animación. Por lo tanto, es una ventana de tiempo innecesaria que no debería estar allí en absoluto, solo la detección de estilo CSS es muy limitada.

@Narretz, si bien la confirmación que proporcionó puede afectar este ejemplo en particular, en realidad no tiene nada que ver con la regresión. La razón de esto es porque el estilo .ng-hide que estaba allí antes de la corrección aplicó el display:none en un momento diferente. Pero la solución actual lo aplica SÓLO después de que se hayan realizado todas las animaciones (una vez que se elimine la clase .ng-animate ).

Eche un vistazo a la demostración a continuación. Vea cómo hay dos conjuntos de selectores para la clase .blue : uno con .ng-animate y sin él. A pesar de que la clase .blue se aplica inmediatamente, ngAnimate todavía cree que se debe realizar una animación y esperará 3s (recuerde 2s * 1.5) antes de aplicar un tiempo de espera de cierre. Normalmente sería 2s, pero un evento animationend nunca se dispara ya que la animación real en el elemento (que está allí debido a .loader ) es infinita y no es activada por ng-class ( o ng-show para el ejemplo anterior). Dicho esto, esto no se ve afectado debido a la corrección de errores anterior.
http://jsfiddle.net/PvS8k/15/

Podría ser mejor hacer ngAnimate menos ingenuo y solo animar cuando animated- esté allí como un prefijo CSS en alguna parte.

Creo que si está abierto a un cambio importante como el manejo de la animación opcional, crearía una experiencia de desarrollador menos sorprendente.

¿Estaría abierto a prefijar algo específico angular como .ng-animate lugar de .animate ?

Tengo el mismo problema:
Con angular> = 1.2.17 http://jsfiddle.net/9krLr/17/
Con angular 1.2.16 todo está bien: http://jsfiddle.net/EZpQQ/1/

@ tole42 Esta es la solución:

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

Gracias por tu ayuda. La solución no funciona :(
¿Qué está mal?
http://jsfiddle.net/9krLr/21/

@ tole42 Nada en ese violín anima, por lo que puedo ver. ¿La animación forma parte de la biblioteca de la Fundación? Un caso de recreación más directo facilitaría la depuración. No me parece el mismo problema.

Creo que veo el mismo problema que @ tole42 . Con ngAnimate include en un módulo, la funcionalidad estándar ng-hide / ng-show no funciona correctamente para el caso base cuando _no_ intenta animarlos. En otras palabras, cuando usa ng-hide / ng-show en un elemento simple sin una clase de animación aplicada.

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

Si quisiera una animación en esa piel, haría algo como:

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

Hay algunos casos en una aplicación en los que es posible que desee animar un espectáculo / ocultar y otros casos en los que no desea animar. En los casos en los que no desea animar, no decora el elemento que se muestra / oculta con ninguna clase de animación personalizada. En este caso, Angular simplemente agrega la clase "ng-hide" a un elemento oculto.

Si no incluye ngAnimate en su módulo, esto funciona como se esperaba: el elemento desaparece inmediatamente. Pero simplemente al incluir ngAnimate, obtienes el comportamiento que se muestra en los dos violines que @ tole42 publicó: hay un retraso antes de que el elemento que obtuvo la clase "ng-hide" agregada desaparezca. Debería desaparecer inmediatamente si no está intentando utilizar animaciones en él.

Un par de soluciones que parecen funcionar son:

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

O:

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

Pero no parece correcto que sean necesarios en el caso de que simplemente intente ocultar algo de una manera no animada.

Solo para dar seguimiento a algunos descubrimientos adicionales ...

Tratando de reducir el problema al escenario más simple posible, mostrando / ocultando divs simples, el problema no se manifiesta.

Noté en los violines publicados por @ tole42 que se estaba utilizando foundation.css, y el ejemplo muestra el problema de mostrar / ocultar campos de entrada. Mi experiencia fue similar (ver el manifiesto del problema con los campos de entrada), pero usando bootstrap.css. Al profundizar en ambos archivos css más de cerca, ambos aplican transiciones css a los campos de entrada.

Esas transiciones css parecen ser las verdaderas culpables, ya que angular-animate está recogiendo las duraciones de ellas. Eso es lo que causa el retraso visual al mostrar / ocultar esos elementos, incluso si no está tratando de animar intencionalmente esa transición.

Así que no creo que este sea necesariamente un problema que Angular debería intentar resolver. Es más un efecto secundario de usar angular-animate con otras bibliotecas css, que pueden tener algunas transiciones css incrustadas que no esperas.

Tomó mucho tiempo rastrear la causa raíz, pero fue bueno finalmente encontrar una razón que tenga sentido.

Sí, este es un problema importante con ngAnimate, pero debido a la falta de control de getComputedStyle y la cascada de transiciones en otras bibliotecas, ngAnimate no puede detectar esto.

Hay dos soluciones para solucionar este problema:

1) Anule el estilo de la clase .ng-animate :
http://jsfiddle.net/9krLr/27/

La razón por la que no le funcionó antes fue por la falta de especificidad de CSS.

2) Utilice $animateProvider.classNameFilter(regex) . La expresión regular en este caso colocará un bloque duro en todas las animaciones activadas por ngAnimate y solo permitirá que la animación tenga lugar si la expresión regular coincide con un className que está presente en el elemento que desea animar.

Oh, poner la configuración en un proveedor es una buena manera de hacerlo, ¡me gusta mucho, @matsko!

@pnutshellmenace gracias por la rápida solución. Me salvó el día.

No entiendo cuál fue la solución final aquí. @matsko declaró:

Podría ser mejor hacer que ngAnimate sea menos ingenuo y solo animar cuando está animado, ¿hay un prefijo CSS en alguna parte?

Pero no veo ninguna implementación como esa. Eché un vistazo a $animateProvider.classNameFilter(regex) pero, de nuevo, me quedan más preguntas que respuestas. ¿Cuál es una forma práctica de implementar esto y qué sucede si hay más de un nombre de clase aplicable?

No veo ninguna razón por la que ngAnimate deba asumir que quiero animar todo. Siempre habrá cosas que no quiero animar, y actualmente tengo más que no quiero animar que al revés, lo que hace que el estilo manual para deshabilitar las transiciones sea poco atractivo.

Editar: Encontré esta entrada de blog que pone las cosas en perspectiva ... Voy a intentarlo: http://blog.fgribreau.com/2014/03/how-to-configure-ng-animate-to- work-on.html

Edición 2: Agregar $animateProvider.classNameFilter(/enable-animate/); funcionó, pero en el proceso encontré un comportamiento interesante:

Había incluido un archivo .js de un módulo angular de terceros que dependía de ngAnimate y, de alguna manera, eso estaba provocando que las animaciones se activaran incluso en mi propio módulo. ¿De alguna manera ngAnimate estaba afectando el alcance del módulo principal?

Preferiría esta respuesta usando $scope.$evalAsync(); para la operación asíncrona. funciona bien.

¿Fue útil esta página
0 / 5 - 0 calificaciones