Angularjs: los elementos ng-cloak / ng-show parpadean

231

Tengo un problema en angular.js con directive / class ng-cloako ng-show.

Chrome funciona bien, pero Firefox está causando el parpadeo de los elementos con ng-cloako ng-show. En mi humilde opinión, es causado por la conversión ng-cloak/ ng-showa style="display: none;", probablemente el compilador de JavaScript de Firefox es un poco más lento, por lo que los elementos aparecen por un tiempo y luego se esconden.

Ejemplo:

<ul ng-show="foo != null" ng-cloak>..</ul>
MelkorNemesis
fuente
1
si configura display: none style en estos elementos inicialmente, ¿soluciona el problema?
akonsu
3
Lo intentaré, estaba intentando algo similar con agregar clase (que oculta el elemento) y luego eliminarlo a través de js manualmente, pero se veía aún más mal.
MelkorNemesis

Respuestas:

385

Aunque la documentación no lo menciona, puede que no sea suficiente agregar la display: none;regla a su CSS. En los casos en que esté cargando angular.js en el cuerpo o las plantillas no se compilan lo suficientemente pronto, use la ng-cloakdirectiva e incluya lo siguiente en su CSS:

/* 
  Allow angular.js to be loaded in body, hiding cloaked elements until 
  templates compile.  The !important is important given that there may be 
  other selectors that are more specific or come later and might alter display.  
 */
[ng\:cloak], [ng-cloak], .ng-cloak {
  display: none !important;
}

Como se menciona en el comentario, el !importantes importante. Por ejemplo, si tiene el siguiente marcado

<ul class="nav">
  <li><a href="/foo" ng-cloak>{{bar}}</a></li>
</ul>

y estás usando bootstrap.css, el siguiente selector es más específico para tu ng-cloakelemento ed

.nav > li > a {
  display: block;
}

Entonces, si incluye una regla simplemente display: none;, la regla de Bootstrap tendrá prioridad y displayse establecerá en block, por lo que verá el parpadeo antes de que se compile la plantilla.

Tim Schaub
fuente
3
También tenga en cuenta que este mismo problema puede ocurrir si está cargando angular.js utilizando un cargador asíncrono, como require.js, porque la regla css en .js no se habrá analizado a tiempo. La solución anterior también corrige este escenario.
Johann
84
No me soluciona el problema. No sé - Creo que los navegadores son demasiado deseoso de mostrar las cosas al principio ...
Andriy Drozdyuk
77
El navegador NUNCA debe representar el DOM sin tener en cuenta el CSS, incluso en el primer paso; eso sería altamente ineficiente; Verifique su configuración: p
AlexG
1
¿Cómo reinicia el dom que ha sido cubierto por ng, una vez que carga vagamente el código del módulo doms?
FutuToad
Si el css anterior no está trabajando para usted es probable que su :en el ng:cloakque no se escapó correctamente. Para CSS puro, asegúrese de que la barra diagonal inversa esté allí. Para CSS compilado, por ejemplo, Stylus, lo será [ng\\:cloak]. Verifique su CSS compilado para asegurarse de que sea correcto.
Joe
47

Como se menciona en la documentación , debe agregar una regla a su CSS para ocultarla en función del ng-cloakatributo:

[ng\:cloak], [ng-cloak], .ng-cloak {
    display: none;
}

Utilizamos trucos similares en el sitio "Construido con Angular", del cual puede ver la fuente en Github: https://github.com/angular/builtwith.angularjs.org

¡Espero que ayude!

btford
fuente
44
angular.js agrega esa regla de estilo al encabezado del documento. Realmente no debería necesitar agregar esto a su CSS. Dicho esto, esto parece funcionar. Supongo que porque angular.js no agrega el bloque de estilo a la cabeza hasta después de cargar angular.
ntownsend
13
Lo que realmente se menciona en la documentación es esto: "Para obtener el mejor resultado, el script angular.js debe cargarse en la sección principal del archivo html; alternativamente , la regla css (arriba) debe incluirse en la hoja de estilo externa de la aplicación. "
Andriy Drozdyuk
44
En otras palabras, si está agregando sus referencias de script en la parte inferior de su página (como lo hace mucha gente); luego agregue la regla a su CSS.
GFoley83
1
Estaba agregando angular.js con require.js, así que esto me ayudó.
oliva
1
Se agregó la directiva ng-cloak al elemento html que contiene la directiva ng-app. Trabajado como un encanto. Ejemplo: <div ng-cloak ng-app = "my-app">
miniscem
33

Asegúrese de que AngularJS esté incluido en headel HTML. Ver ngCloak doc :

Para obtener el mejor resultado, el script angular.js debe cargarse en la sección de cabecera del archivo html; alternativamente, la regla css (arriba) debe incluirse en la hoja de estilo externa de la aplicación.

Andriy Drozdyuk
fuente
3
¡si! No puedo entender por qué la gente en todas partes parece recomendar cargar angular.js al final de la página. Me siento mejor si Angular toma el control desde el principio. Mi ng-cloakestá trabajando ahora.
Ivan Ferrer Villa
2
Estoy de acuerdo: lo que pasa con los scripts que se cargan al final proviene del desarrollo web normal donde desea que la página muestre algo antes de que js haga lo suyo, pero en el caso de angular, realmente desea lo contrario.
ver más agudo
1
Y antes de que se carguen las hojas de estilo. Incluir Angular en la headhoja de estilo, pero después, incluye, no soluciona el problema.
AgmLauncher
27

Nunca he tenido mucha suerte usando ngCloak. Todavía me parpadeo a pesar de todo lo mencionado anteriormente. La única forma segura de evitar el movimiento rápido es colocar su contenido en una plantilla e incluirla. En un SPA, el único HTML que se evaluará antes de ser compilado por Angular es su página index.html principal.

Simplemente tome todo dentro del cuerpo y péguelo en un archivo separado y luego:

<ng-include src="'views/indexMain.html'"></ng-include>

Nunca debería parpadear de esa manera, ya que Angular compilará la plantilla antes de agregarla al DOM.

Matt Hughes
fuente
1
Exactamente lo que uso: limpio y simple, sin trucos dolorosos.
Dmitri Zaitsev
2
Tenga en cuenta que ng-includegenera una solicitud AJAX adicional para obtener el contenido del servidor. Aprendí por las malas que nunca deberías usar ng-includedentro ng-repeat, por ejemplo.
jsuddsjr
1
trabajó para mi. recuerde mantenerse ng-appfuera de la ng-includeen su marcado.
GraehamF
2
Esta solución funciona mejor, sin ningún tipo de hipo. Si es posible, use esta solución.
idungotnosn 01 de
2
Esta solución solucionó una situación realmente molesta. ¡Gracias!
Maxwelll
22

ngBind y ngBindTemplate son alternativas que no requieren CSS:

<div ng-show="foo != null" ng-cloak>{{name}}</div>  <!-- requires CSS -->
<div ng-show="foo != null" ng-bind="name"></div>
<div ng-show="foo != null" ng-bind-template="name = {{name}}"></div>
Mark Rajcok
fuente
1
Buena respuesta simple. ng-bindes una buena manera de evitar el 'flash de llaves' o tener que usarlo ng-cloaka nivel de etiqueta, aunque algunas personas piensan que hace que el código sea menos legible. Para ellos, no veo una razón para no mezclar los dos enfoques.
Dave Everitt el
1
ng-bind es un enfoque mucho mejor para el problema, ya que las otras respuestas requieren que cargue el primer ángulo angular, sin parpadeos de llaves en ninguna circunstancia
legramira
20

Además de la respuesta aceptada si está utilizando un método alternativo para activar ng-cloak ...

También es posible que desee agregar algunas especificidades adicionales a su CSS / LESS:

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide {
    display: none !important;
}
Corey Ballou
fuente
1
Esto funcionó para mi caso de uso, cuando ninguno de los anteriores parecía hacer el trabajo.
Porlune
15

Tuve un problema similar y descubrí que si tienes una clase que contiene transiciones, el elemento parpadeará. Traté de agregar ng-cloak sin éxito, pero al eliminar la transición, el botón dejó de parpadear.

Estoy usando el marco iónico y el contorno del botón tiene esta transición

.button-outline {
  -webkit-transition: opacity .1s;
  transition: opacity .1s;
}

Simplemente sobrescriba la clase para eliminar la transición y el botón dejará de parpadear.

Actualizar

De nuevo en iónico hay un parpadeo cuando se usa ng-show / ng-hide. Agregar el siguiente CSS lo resuelve:

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

Fuente: http://forum.ionicframework.com/t/beta-14-ng-hide-show/14270/9

Seb Fanals
fuente
1
¿Pero eso no deshabilitaría las animaciones para las directivas ng-hide / show?
Kushagra Gour
1
No me acuerdo ¿Lo probaste y ha desactivado las animaciones?
Seb Fanals
1
Gracias. Este es un problema muy especial en iónico. He añadido .button-clear, .button-icon, .button-outline { @include transition(opacity 0s); }a mi SCSS.
hgoebl
9

Tuve un problema en el que a <div ng-show="expression">sería inicialmente visible durante una fracción de segundo, a pesar de que "expresión" era inicialmente falsa, antes de que la directiva ng-show tuviera la oportunidad de ejecutarse.

La solución que utilicé fue agregar manualmente la clase "ng-hide", como en <div ng-show="expression" ng-hide>, para asegurarme de que comenzó inicialmente oculto. La directiva ng-show agregará / eliminará la clase ng-hide según sea necesario después de eso.

metamatt
fuente
1
wow, de todas las malditas opciones que probé, esto funcionó. ¡Gracias!
Nikola
¡Mejor solución! ¡Esto me volvió loco durante varios meses! ¡Gracias!
abelabbesnabi
Estoy usando el marco iónico y esta es la única respuesta que realmente funciona
Mikel el
7

Intenta apagar el Firebug . Lo digo en serio. Esto ayuda en mi caso.

Aplique la respuesta aceptada y luego asegúrese de que Firebug en su Firefox esté apagado : presione F12 y luego apague Firebug para esta página: pequeño botón en la esquina superior derecha.

CoperNick
fuente
Sí, eso lo hizo por mí ¡Gracias!
MadeInDreams
Gracias, eso me estaba volviendo loco. Raro insecto
Stephen Simpson
6

En realidad, hay dos problemas separados que pueden causar el problema de parpadeo y podría enfrentarse a uno o ambos.

Problema 1: ng-cloak se aplica demasiado tarde

Este problema se resuelve como se describe en muchas de las respuestas en esta página para asegurarse de que AngularJS esté cargado en la cabeza. Ver ngCloak doc :

Para obtener el mejor resultado, el script angular.js debe cargarse en la sección de cabecera del archivo html; alternativamente, la regla css (arriba) debe incluirse en la hoja de estilo externa de la aplicación.

Problema 2: ng-cloak se quita demasiado pronto

Es muy probable que este problema ocurra cuando tiene una gran cantidad de CSS en su página con reglas en cascada entre sí y las capas más profundas de CSS parpadean antes de que se aplique la capa superior.

Las soluciones jQuery en las respuestas que implican agregar style="display:none"a su elemento resuelven este problema siempre que el estilo se elimine lo suficientemente tarde (de hecho, estas soluciones resuelven ambos problemas). Sin embargo, si prefiere no agregar estilos directamente a su HTML, puede lograr los mismos resultados con ng-show.

Comenzando con el ejemplo de la pregunta:

<ul ng-show="foo != null" ng-cloak>..</ul>

Agregue una regla ng-show adicional a su elemento:

<ul ng-show="isPageFullyLoaded && (foo != null)" ng-cloak>..</ul>

(Debe mantener ng-cloakpara evitar el problema 1).

Luego, en su conjunto de aplicaciones isPageFullyLoaded.

app.run(['$rootScope', function ($rootScope) {
    $rootScope.$safeApply = function (fn) {
        $rootScope.isPageFullyLoaded = true;
    }
}]);

Tenga en cuenta que, dependiendo de exactamente lo que esté haciendo, app.run puede o no ser el mejor lugar para configurar isPageFullyLoaded. Lo importante es asegurarse de que isPageFullyLoadedse establezca como verdadero después de que lo que no desea parpadear esté listo para ser revelado al usuario.

Parece que el problema 1 es el problema que está enfrentando el OP, pero otros están descubriendo que la solución no funciona o solo funciona parcialmente porque están golpeando el problema 2 en su lugar o también.

Nota importante: asegúrese de aplicar soluciones tanto a la capa ng que se aplica demasiado tarde como a la que se retira demasiado pronto. Resolver solo uno de estos problemas puede no aliviar los síntomas.

Andrew Downes
fuente
1
esto lo solucionó para mí "el script debe cargarse en la sección de cabecera"
aliopi
4

Nos encontramos con este problema en nuestra empresa y lo resolvimos agregando "display: none" al estilo CSS para esos elementos parpadeantes de ng-show. No tuvimos que usar ng-cloak en absoluto. A diferencia de otros en este hilo, experimentamos este problema en Safari pero no en Firefox o Chrome, posiblemente debido al error de repintado perezoso de Safari en iOS7 .

Jake McGuire
fuente
3

Por lo que vale, tuve un problema similar ng-cloak no funciona. Puede valer la pena revisar su aplicación / sitio con el caché habilitado para reutilizar los archivos de origen para ver si eso ayuda.

Con mi encuentro con parpadeo, estaba probando con DevTools abierto y el caché deshabilitado. Dejar el panel cerrado con el almacenamiento en caché habilitado solucionó mi problema.

mrdazm
fuente
3

Mantener las siguientes declaraciones en la etiqueta principal solucionó este problema

<style type="text/css">
    [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
    display: none !important;
}
</style>

documentación oficial

Saikiran K
fuente
3

No pude lograr que ninguno de estos métodos funcionara, así que eventualmente hice lo siguiente. Para el elemento que desea inicialmente oculto:

<div <!--...--> style="display: none;" ng-style="style">

Luego, en su controlador, agregue esto en o cerca de la parte superior:

$scope.style = { display: 'block' };

De esta manera, el elemento se oculta inicialmente y solo se muestra cuando el código del controlador se ha ejecutado realmente.

Puede ajustar la ubicación a sus necesidades, quizás agregando algo de lógica. En mi caso, cambio a una ruta de inicio de sesión si no estoy conectado actualmente, y no quería que mi interfaz parpadeara de antemano, así que configuré $scope.styledespués de la verificación de inicio de sesión.

shawkinaw
fuente
2

Es mejor usar en ng-iflugar de ng-show. ng-if Elimina y recrea completamente el elemento en el DOM y ayuda a evitar el parpadeo de ng-shows.

alexey
fuente
pero también destruye cualquier complemento en ejecución en esa parte de la dom ... (por ejemplo: jquery ui)
Geert Bellemans
2

será mejor que haga referencia al documento angular, porque la versión [1.4.9] tiene una actualización a continuación que hace que sea compatible con la directiva data-ng-cloak.

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  display: none !important;
}
Nathan
fuente
2

Probé la solución ng-cloak anterior pero todavía tiene problemas intermitentes con Firefox. La única solución que funcionó para mí es retrasar la carga del formulario hasta que Angular esté completamente cargado.

Simplemente agregué ng-init en la aplicación y uso ng-if en el lado del formulario para verificar si la variable que configuré ya está cargada.

<div ng-app="myApp" ng-init="loaded='yes'"> 
   <form ng-if="loaded.length > 0">
      <!--all my elements here-->
   </form>
</div>
java25
fuente
1

Además de otras respuestas, si encuentra que el código de plantilla todavía está ocurriendo, es probable que tenga sus scripts en la parte inferior de la página y eso significa que la directiva ng-cloak directamente no funcionará. Puede mover sus scripts a la cabeza o crear una regla CSS.

Los documentos dicen "Para obtener el mejor resultado, el script angular.js debe cargarse en la sección principal del documento html; alternativamente, la regla css anterior debe incluirse en la hoja de estilo externa de la aplicación".

Ahora, no tiene que ser una hoja de estilo externa sino solo un elemento en la cabeza.

<style type="text/css">
  .ng-cloak {
    display: none !important;
  }
</style>

fuente: https://docs.angularjs.org/api/ng/directive/ngCloak

Elijah Lynn
fuente
1

Probé todas las soluciones publicadas aquí y aún parpadeo en Firefox.

Si ayuda a alguien, lo resolví agregando style="display: none;"al contenido principal div, luego usando jQuery (ya lo estaba usando en la página) $('#main-div-id').show();una vez que todo se cargó después de obtener datos del servidor;

hipnosis
fuente
Descubrí que esta era la única solución que funcionó para mí, pero quería evitar usar JQuery, así que encontré una alternativa. Vea mi respuesta aquí: stackoverflow.com/a/42527700/4214694
Andrew Downes
1

De hecho, encontré que la sugerencia del registro web de Rick Strahl solucionó mi problema perfectamente (ya que todavía tenía el extraño problema de que ng-cloak parpadeaba en bruto {{code}} a veces, especialmente mientras ejecutaba Firebug):

La opción nuclear: ocultar el contenido manualmente

Usar el CSS explícito es la mejor opción, por lo que lo siguiente no debería ser necesario. Pero lo mencionaré aquí, ya que brinda una idea de cómo puede ocultar / mostrar contenido manualmente al cargarlo para otros marcos o en sus propias plantillas basadas en marcado.

Antes de darme cuenta de que podía incorporar explícitamente el estilo CSS en la página, había intentado averiguar por qué ng-cloak no estaba haciendo su trabajo. Después de perder una hora en llegar a ninguna parte, finalmente decidí ocultar y mostrar manualmente el contenedor. La idea es simple: inicialmente oculte el contenedor, luego muéstrelo una vez que Angular haya realizado su procesamiento inicial y elimine el marcado de la plantilla de la página.

Puede ocultar manualmente el contenido y hacerlo visible después de que Angular haya obtenido el control. Para hacer esto utilicé:

<div id="mainContainer" class="mainContainer boxshadow"
    ng-app="app" style="display:none">

Observe la visualización: ningún estilo que oculta explícitamente el elemento inicialmente en la página.

Luego, una vez que Angular haya ejecutado su inicialización y procesado efectivamente el marcado de la plantilla en la página, puede mostrar el contenido. Para Angular, este evento 'listo' es la función app.run ():

app.run( function ($rootScope, $location, cellService) {        
    $("#mainContainer").show();
    
});

Esto elimina efectivamente la pantalla: ninguno de estilo y el contenido se muestra. En el momento en que se activa app.run (), el DOM está listo para mostrarse con datos llenos o al menos datos vacíos: Angular ha obtenido el control.

Campbeln
fuente
Descubrí que esta era la única solución que funcionó para mí, pero quería evitar usar JQuery, así que encontré una alternativa. Vea mi respuesta aquí: stackoverflow.com/a/42527700/4214694
Andrew Downes el
1

Intenté todas las respuestas anteriores y nada funcionó. Utilicé iónico para desarrollar una aplicación híbrida e intenté hacer que un mensaje de error no parpadeara. Terminé resolviendo mi problema agregando una clase ng-hide a mi elemento. Mi div ya tiene ng-show para mostrar el elemento cuando hay un error. Agregar ng-hide establece que el div no se muestre antes de cargar angular. No es necesario usar capa ng o agregar angular a la cabeza

gyleg5
fuente
1

AS de la discusión anterior

[ng-cloak] {
                display: none;
            }

es la manera perfecta de resolver el problema.

Dinesh Jain
fuente
1

Estoy usando ng-show en una directiva para mostrar y ocultar ventanas emergentes.

<div class="..." ng-show="showPopup">

Nada de lo anterior funcionó para mí, y usar ng-if en lugar de ng-show sería una exageración. Eso implicaría eliminar y agregar todo el contenido emergente en el DOM con cada clic. En cambio, agregué un ng-if en el mismo elemento para asegurarme de que no se muestre en la carga del documento:

<div class="..." ng-show="showPopup" ng-if="popupReady">

Luego agregué la inicialización en el controlador responsable de esta directiva con un tiempo de espera:

$timeout(function () {
    $scope.popupReady = true;
});

De esta forma eliminé el problema de parpadeo y evité la costosa operación de inserción de DOM con cada clic. Esto vino a expensas de usar dos variables de alcance para el mismo propósito en lugar de una, pero hasta ahora esta es definitivamente la mejor opción.

mano abajo
fuente
1

Intenté ng-cloakpero aún breves parpadeos. El siguiente código los libró por completo.

<body style="display:none;" ng-style="{'display':'block'}">
Abu Abdullah
fuente
1

Ninguna de las soluciones enumeradas anteriormente funcionó para mí. Entonces decidí mirar la función real y me di cuenta de que cuando se disparó "$ scope.watch", estaba poniendo un valor en el campo de nombre que no estaba destinado a ser el caso. Entonces, en el código que configuré y oldValue y newValue luego

$scope.$watch('model.value', function(newValue, oldValue) {
if (newValue !== oldValue) {
validateValue(newValue);
}
});

Esencialmente cuando se dispara scope.watch en este caso, AngularJS monitorea los cambios en la variable de nombre (model.value)

D.Adelakun
fuente
0

Lo envolvería <ul>con un<div ng-cloak>

Dan Doyon
fuente
2
No debería necesitar envolver el <ul>. ng-cloakocultará cualquier elemento al que se aplique, así como a los descendientes de ese elemento.
btford
0

Personalmente decidí usar el ng-classatributo en lugar del ng-show. He tenido mucho más éxito en esta ruta, especialmente para las ventanas emergentes que no siempre se muestran por defecto.

Lo que solía ser <div class="options-modal" ng-show="showOptions"></div>

es ahora: <div class="options-modal" ng-class="{'show': isPrintModalShown}">

con el CSS para la clase modal de opciones display: nonepor defecto. La clase show contiene el display:blockCSS.

Mi pila se desborda
fuente
-2

Evite el salto de línea

<meta http-equiv="Content-Security-Policy"              content="
default-src 'FOO';   
script-src 'FOO';    
style-src  'FOO'; 
font-src 'FOO';">

Funciona con Firefox 45.0.1

<meta http-equiv="Content-Security-Policy"              content="    default-src 'FOO';    script-src 'FOO';     style-src  'FOO';    font-src 'FOO';">
Espigah
fuente