Angularjs - Les éléments ng-cloak / ng-show clignotent

231

J'ai un problème dans angular.js avec directive / classe ng-cloakou ng-show.

Chrome fonctionne bien, mais Firefox fait clignoter des éléments avec ng-cloakou ng-show. À mon humble avis, il est causé par la conversion ng-cloak/ ng-showen style="display: none;", probablement le compilateur javascript de Firefox est un peu plus lent, donc les éléments apparaissent pendant un certain temps, puis se cachent?

Exemple:

<ul ng-show="foo != null" ng-cloak>..</ul>
MelkorNemesis
la source
1
si vous définissez le style d'affichage: aucun style sur ces éléments au départ, cela résout-il le problème?
akonsu
3
J'essaierai cela, j'essayais quelque chose de similaire avec l'ajout de classe (qui masque l'élément), puis la suppression via js manuellement, mais cela semblait encore plus mauvais.
MelkorNemesis

Réponses:

385

Bien que la documentation ne le mentionne pas, il ne suffira peut-être pas d'ajouter la display: none;règle à votre CSS. Dans les cas où vous chargez angular.js dans le corps ou si les modèles ne sont pas compilés assez tôt, utilisez la ng-cloakdirective et incluez les éléments suivants dans votre 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;
}

Comme mentionné dans le commentaire, le !importantest important. Par exemple, si vous disposez du balisage suivant

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

et que vous utilisez bootstrap.css, le sélecteur suivant est plus spécifique pour votre ng-cloakélément ed

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

Donc, si vous incluez une règle avec simplement display: none;, la règle de Bootstrap aura la priorité et displaysera définie sur block, vous verrez donc le scintillement avant la compilation du modèle.

Tim Schaub
la source
3
Notez également que ce même problème peut se produire si vous chargez angular.js à l'aide d'un chargeur asynchrone, tel que require.js, car la règle css dans le .js n'aura pas été analysée à temps. La solution ci-dessus corrige également ce scénario.
Johann
84
Ne résout pas le problème pour moi. Je ne sais pas - je pense que les navigateurs sont trop désireux de montrer les choses au début ...
Andriy Drozdyuk
7
Le navigateur ne doit JAMAIS restituer le DOM sans prendre en compte le CSS, même lors de la première passe; ce serait très inefficace; Vérifiez votre configuration: p
AlexG
1
comment pouvez-vous redémarrer le dom qui a été masqué, une fois que vous avez paresseusement chargé le code du module doms?
FutuToad
Si le code CSS ci - dessus ne fonctionne pas pour vous les chances sont votre :en ng:cloakest pas échappé correctement. Pour du CSS pur, assurez-vous que la barre oblique inverse est là. Pour les css compilés, par exemple Stylus, ce sera le cas [ng\\:cloak]. Vérifiez votre CSS compilé pour vous assurer qu'il est correct.
Joe
47

Comme mentionné dans la documentation , vous devez ajouter une règle à votre CSS pour la masquer en fonction de l' ng-cloakattribut:

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

Nous utilisons des astuces similaires sur le site "Built with Angular", dont vous pouvez voir la source sur Github: https://github.com/angular/builtwith.angularjs.org

J'espère que cela pourra aider!

btford
la source
4
angular.js ajoute cette règle de style en tête du document. Vous ne devriez vraiment pas avoir besoin d'ajouter cela à votre CSS. Cela dit, cela semble fonctionner. Ma supposition est parce que angular.js n'ajoute pas le bloc de style à la tête jusqu'à ce que le chargement angulaire soit terminé.
ntownsend
13
Ce qui est vraiment mentionné dans la documentation est le suivant: "Pour le meilleur résultat, le script angular.js doit être chargé dans la section head du fichier html; en variante , la règle css (ci-dessus) doit être incluse dans la feuille de style externe de l'application. "
Andriy Drozdyuk
4
En d'autres termes, si vous ajoutez vos références de script au bas de votre page (comme beaucoup de gens le font); puis ajoutez la règle à votre CSS.
GFoley83
1
J'ajoutais angular.js avec require.js, donc cela m'a aidé.
olive
1
Ajout de la directive ng-cloak à l'élément html abritant la directive ng-app. A fonctionné comme un charme. Exemple: <div ng-cloak ng-app = "my-app">
miniscem
33

Assurez-vous que AngularJS est inclus dans headle HTML. Voir le document ngCloak :

Pour un résultat optimal, le script angular.js doit être chargé dans la section head du fichier html; alternativement, la règle css (ci-dessus) doit être incluse dans la feuille de style externe de l'application.

Andriy Drozdyuk
la source
3
Oui! Je ne comprends pas pourquoi les gens du monde entier semblent recommander de charger angular.js à la fin de la page. Je me sens mieux si Angular prend le contrôle dès le début. Mon ng-cloaktravaille maintenant.
Ivan Ferrer Villa
2
Je suis d'accord - le fait que les scripts soient chargés à la fin vient du développement Web normal où vous voulez que la page affiche quelque chose avant que le js ne fasse son travail, mais dans le cas d'angulaire, vous voulez en fait l'inverse.
voir plus net
1
ET avant le chargement des feuilles de style. L'inclusion d'Angular dans la headfeuille de style, mais après, ne résout pas le problème.
AgmLauncher
27

Je n'ai jamais eu beaucoup de chance avec ngCloak. Je scintille toujours malgré tout ce qui est mentionné ci-dessus. Le seul moyen infaillible d'éviter le feuilletage est de mettre votre contenu dans un modèle et d'inclure le modèle. Dans un SPA, le seul HTML qui sera évalué avant d'être compilé par Angular est votre page principale index.html.

Il suffit de tout prendre à l'intérieur du corps et de le coller dans un fichier séparé, puis:

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

Vous ne devriez jamais avoir de scintillement de cette façon car Angular compilera le modèle avant de l'ajouter au DOM.

Matt Hughes
la source
1
Exactement ce que j'utilise - propre et simple, pas de hacks douloureux.
Dmitri Zaitsev
2
Veuillez noter que ng-includegénère une demande AJAX supplémentaire pour récupérer le contenu du serveur. J'ai appris à la dure que vous ne devriez jamais utiliser à l' ng-includeintérieur ng-repeat, par exemple.
jsuddsjr
1
travaillé pour moi. n'oubliez pas de garder en ng-appdehors du ng-includedans votre balisage.
GraehamF
2
Cette solution fonctionne mieux, sans aucun hoquet. Si possible, utilisez cette solution.
idungotnosn du
2
Cette solution a corrigé une situation vraiment ennuyeuse. Je vous remercie!
Maxwelll
22

ngBind et ngBindTemplate sont des alternatives qui ne nécessitent pas de 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
la source
1
Belle réponse simple. ng-bindest un bon moyen d'éviter le «flash d'accolade» ou de devoir l'utiliser ng-cloakau niveau de la balise, bien que certaines personnes pensent que cela rend le code moins lisible. Pour eux, je ne vois pas de raison de ne pas mélanger les deux approches.
Dave Everitt
1
ng-bind est une bien meilleure approche du problème car les autres réponses vous demandent de charger d'abord les accolades angulaires, pas de bretelles frisées clignotent en toutes circonstances
legramira
20

En plus de la réponse acceptée si vous utilisez une autre méthode de déclenchement de ng-cloak ...

Vous pouvez également souhaiter ajouter quelques spécificités supplémentaires à votre CSS / LESS:

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide {
    display: none !important;
}
Corey Ballou
la source
1
Cela a fonctionné pour mon cas d'utilisation, quand aucun des éléments ci-dessus ne semblait faire le travail.
Porlune
15

J'ai eu un problème similaire et j'ai découvert que si vous avez une classe qui contient des transitions, l'élément clignotera. J'ai essayé d'ajouter ng-cloak sans succès, mais en supprimant la transition, le bouton a cessé de clignoter.

J'utilise un cadre ionique et le contour du bouton a cette transition

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

Remplacez simplement la classe pour supprimer la transition et le bouton cessera de clignoter.

Mettre à jour

Toujours sur ionique, il y a un scintillement lors de l'utilisation de ng-show / ng-hide. L'ajout du CSS suivant le résout:

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

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

Seb Fanals
la source
1
Mais cela ne désactiverait-il pas les animations pour les directives ng-hide / show?
Kushagra Gour
1
Je ne m'en souviens pas. Vous l'avez essayé et il a désactivé les animations?
Seb Fanals
1
Merci. C'est un problème très spécial sur ionique. J'ai ajouté.button-clear, .button-icon, .button-outline { @include transition(opacity 0s); } à mon scss.
hgoebl
9

J'ai eu un problème où a <div ng-show="expression">serait initialement visible pendant une fraction de seconde, même si "expression" était initialement fausse, avant que la directive ng-show n'ait une chance de s'exécuter.

La solution que j'ai utilisée était d'ajouter manuellement la classe "ng-hide", comme dans <div ng-show="expression" ng-hide>, pour s'assurer qu'elle a commencé initialement cachée. La directive ng-show ajoutera / supprimera la classe ng-hide si nécessaire après cela.

metamatt
la source
1
wow, parmi toutes les options flippantes que j'ai essayées, cela a fait l'affaire. Je vous remercie!
Nikola
Meilleure solution! Cela m'a rendu fou pendant plusieurs mois! Je vous remercie!
abelabbesnabi
J'utilise un cadre ionique et c'est la seule réponse qui fonctionne réellement
Mikel
7

Essayez d' éteindre le Firebug . Je suis serieux. Cela aide dans mon cas.

Appliquez la réponse acceptée et assurez-vous que Firebug dans votre Firefox est désactivé : appuyez sur F12 puis désactivez Firebug pour cette page - petit bouton dans le coin supérieur droit.

CoperNick
la source
Oui, ça l'a fait pour moi Merci!
MadeInDreams
Merci, cela me rendait fou. Bug
Stephen Simpson
6

Il y a en fait deux problèmes distincts qui peuvent causer le problème de scintillement et vous pourriez être confronté à l'un ou aux deux.

Problème 1: ng-cloak est appliqué trop tard

Ce problème est résolu comme décrit dans de nombreuses réponses sur cette page est de s'assurer que AngularJS est chargé dans la tête. Voir le document ngCloak :

Pour un résultat optimal, le script angular.js doit être chargé dans la section head du fichier html; alternativement, la règle css (ci-dessus) doit être incluse dans la feuille de style externe de l'application.

Problème 2: ng-cloak est supprimé trop tôt

Ce problème est plus susceptible de se produire lorsque vous avez beaucoup de CSS sur votre page avec des règles en cascade les unes sur les autres et que les couches profondes de CSS clignotent avant que la couche supérieure ne soit appliquée.

Les solutions jQuery dans les réponses impliquant l'ajout style="display:none"à votre élément résolvent ce problème tant que le style est supprimé suffisamment tard (en fait, ces solutions résolvent les deux problèmes). Cependant, si vous préférez ne pas ajouter de styles directement à votre code HTML, vous pouvez obtenir les mêmes résultats en utilisant ng-show.

En commençant par l'exemple de la question:

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

Ajoutez une règle ng-show supplémentaire à votre élément:

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

(Vous devez continuer ng-cloakà éviter le problème 1).

Ensuite, dans votre ensemble app.run isPageFullyLoaded:

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

Sachez que selon exactement ce que vous faites, app.run peut ou non être le meilleur endroit à définir isPageFullyLoaded. L'important est de s'assurer que la valeur isPageFullyLoadedtrue après tout ce que vous ne voulez pas scintiller est prête à être révélée à l'utilisateur.

Il semble que le problème 1 soit le problème que l'OP rencontre, mais d'autres trouvent que la solution ne fonctionne pas ou ne fonctionne que partiellement parce qu'ils rencontrent le problème 2 à la place ou également.

Remarque importante: assurez-vous d'appliquer les solutions aux deux ng-cloak appliqués trop tard ET retirés trop tôt. La résolution d'un seul de ces problèmes peut ne pas soulager les symptômes.

Andrew Downes
la source
1
cela l'a corrigé pour moi "le script doit être chargé dans la section head"
aliopi
4

Nous avons rencontré ce problème dans notre entreprise et l'avons résolu en ajoutant "display: none" au style CSS pour ces éléments clignotants de ng-show. Nous n'avions pas du tout besoin d'utiliser ng-cloak. Contrairement à d'autres dans ce fil, nous avons rencontré ce problème dans Safari, mais pas Firefox ou Chrome, probablement en raison du bogue de repeindre paresseux de Safari dans iOS7 .

Jake McGuire
la source
3

Pour ce que ça vaut, j'ai eu un problème similaire ng-cloak ne fonctionnant pas. Il peut être utile de vérifier votre application / site avec le cache activé pour réutiliser les fichiers source pour voir si cela aide.

Avec mon rodage avec scintillement, je testais avec DevTools ouvert et cache désactivé. Laisser le panneau fermé avec la mise en cache activée a résolu mon problème.

mrdazm
la source
3

Garder les instructions ci-dessous dans la balise head a résolu ce problème

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

documentation officielle

Saikiran K
la source
3

Je n'ai pu faire fonctionner aucune de ces méthodes, j'ai donc fini par faire ce qui suit. Pour l'élément que vous souhaitez initialement masquer:

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

Ensuite, dans votre contrôleur, ajoutez ceci en haut ou près du haut:

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

De cette façon, l'élément est initialement masqué et ne s'affiche que lorsque le code du contrôleur s'est réellement exécuté.

Vous pouvez adapter le placement à vos besoins, en ajoutant peut-être un peu de logique. Dans mon cas, je passe à un chemin de connexion si je ne suis pas actuellement connecté, et je ne voulais pas que mon interface scintille au préalable, alors je me suis mis $scope.styleaprès la vérification de connexion.

shawkinaw
la source
2

Il vaut mieux utiliser à la ng-ifplace de ng-show. ng-if supprime et recrée complètement l'élément dans le DOM et aide à éviter le clignotement de ng-shows.

alexey
la source
mais il détruit également tous les plugins en cours d'exécution sur cette partie du dom ... (ex: jquery ui)
Geert Bellemans
2

vous feriez mieux de référencer un document angulaire, car la version [1.4.9] a une mise à jour ci-dessous qui pourrait prendre en charge la directive data-ng-cloak.

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

J'ai essayé la solution ng-cloak ci-dessus mais elle a toujours des problèmes intermittents avec Firefox. La seule solution de contournement qui a fonctionné pour moi est de retarder le chargement du formulaire jusqu'à ce que Angular soit complètement chargé.

J'ai simplement ajouté ng-init dans l'application et j'utilise ng-if côté formulaire pour vérifier si la variable que j'ai définie est déjà chargée.

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

En plus d'autres réponses, si vous trouvez que le code flash du modèle se produit toujours, il est probable que vous ayez vos scripts en bas de la page et cela signifie que la directive ng-cloak ne fonctionnera pas. Vous pouvez soit déplacer vos scripts vers la tête, soit créer une règle CSS.

Les documents indiquent "Pour un résultat optimal, le script angular.js doit être chargé dans la section head du document html; en variante, la règle css ci-dessus doit être incluse dans la feuille de style externe de l'application."

Maintenant, il ne doit pas être une feuille de style externe mais juste dans un élément dans la tête.

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

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

Elijah Lynn
la source
1

J'ai essayé toutes les solutions publiées ici et je scintillais toujours dans Firefox.

Si cela aide quelqu'un, je l'ai résolu en ajoutant style="display: none;"au contenu principal div, puis en utilisant jQuery (je l'utilisais déjà sur la page) $('#main-div-id').show();une fois que tout était chargé après avoir obtenu des données du serveur;

hipnose
la source
J'ai trouvé que c'était la seule solution qui fonctionnait pour moi, mais je voulais éviter d'utiliser JQuery, j'ai donc trouvé une alternative. Voir ma réponse ici: stackoverflow.com/a/42527700/4214694
Andrew Downes
1

J'ai trouvé la suggestion du journal Web de Rick Strahl parfaitement mon problème (car j'avais toujours le problème étrange avec ng-cloak clignotant brut {{code}} parfois, surtout lors de l'exécution de Firebug):

L'option nucléaire: masquer le contenu manuellement

L'utilisation du CSS explicite est le meilleur choix, donc ce qui suit ne devrait jamais être nécessaire. Mais je le mentionnerai ici car il donne un aperçu de la façon dont vous pouvez masquer / afficher le contenu manuellement lors du chargement pour d'autres cadres ou dans vos propres modèles basés sur le balisage.

Avant de comprendre que je pouvais intégrer explicitement le style CSS dans la page, j'avais essayé de comprendre pourquoi ng-cloak ne faisait pas son travail. Après avoir perdu une heure pour aller nulle part, j'ai finalement décidé de cacher et d'afficher manuellement le conteneur. L'idée est simple: masquez d'abord le conteneur, puis affichez-le une fois qu'Angular a effectué son traitement initial et supprimé le balisage du modèle de la page.

Vous pouvez masquer manuellement le contenu et le rendre visible une fois que Angular a pris le contrôle. Pour ce faire, j'ai utilisé:

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

Remarquez le style d'affichage: aucun qui masque explicitement l'élément initialement sur la page.

Une fois qu'Angular a exécuté son initialisation et traité efficacement le balisage du modèle sur la page, vous pouvez afficher le contenu. Pour Angular, cet événement «prêt» est la fonction app.run ():

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

Cela supprime efficacement l'affichage: aucun style et le contenu s'affiche. Au moment où app.run () se déclenche, le DOM est prêt à être affiché avec des données remplies ou au moins des données vides - Angular a pris le contrôle.

Campbeln
la source
J'ai trouvé que c'était la seule solution qui fonctionnait pour moi, mais je voulais éviter d'utiliser JQuery, j'ai donc trouvé une alternative. Voir ma réponse ici: stackoverflow.com/a/42527700/4214694
Andrew Downes
1

J'ai essayé toutes les réponses ci-dessus et rien n'a fonctionné. Utiliser ionic pour développer une application hybride et essayait de ne pas faire scintiller un message d'erreur. J'ai fini par résoudre mon problème en ajoutant une classe ng-hide à mon élément. Mon div a déjà ng-show pour montrer l'élément quand il y a une erreur. L'ajout de ng-hide définit le div à ne pas s'afficher avant le chargement angulaire. Aucun ng-manteau ou ajout angulaire à la tête nécessaire.

gyleg5
la source
1

AS de la discussion ci-dessus

[ng-cloak] {
                display: none;
            }

est le moyen idéal pour résoudre le problème.

Dinesh Jain
la source
1

J'utilise ng-show dans une directive pour afficher et masquer les popups.

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

Rien de ce qui précède n'a fonctionné pour moi, et utiliser ng-if au lieu de ng-show serait une exagération. Cela impliquerait de supprimer et d'ajouter tout le contenu contextuel dans le DOM à chaque clic. Au lieu de cela, j'ai ajouté un ng-if dans le même élément pour m'assurer qu'il ne s'affiche pas lors du chargement du document:

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

Ensuite, j'ai ajouté l'initialisation dans le contrôleur responsable de cette directive avec un timeout:

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

De cette façon, j'ai éliminé le problème de scintillement et évité l'opération coûteuse d'insertion DOM à chaque clic. Cela s'est fait au détriment de l'utilisation de deux variables d'étendue dans le même but au lieu d'une, mais jusqu'à présent, c'est certainement la meilleure option.

renversé
la source
1

Clignotements essayés ng-cloakmais toujours brefs. Le code ci-dessous les débarrasse complètement.

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

Aucune des solutions énumérées ci-dessus n'a fonctionné pour moi. J'ai alors décidé de regarder la fonction réelle et j'ai réalisé que lorsque «$ scope.watch» était lancé, il mettait une valeur dans le champ de nom qui n'était pas censée être le cas. Donc, dans le code que j'ai défini et oldValue et newValue puis

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

Essentiellement lorsque scope.watch est déclenché dans ce cas, AngularJS surveille les modifications apportées à la variable de nom (model.value)

D.Adelakun
la source
0

Je voudrais envelopper le <ul>avec<div ng-cloak>

Dan Doyon
la source
2
Il ne devrait pas avoir besoin d'envelopper <ul>. ng-cloakmasquera l'élément auquel il est appliqué, ainsi que les descendants de cet élément.
btford
0

J'ai personnellement décidé d'utiliser l' ng-classattribut plutôt que leng-show . J'ai eu beaucoup plus de succès dans cette voie, en particulier pour les fenêtres contextuelles qui ne sont pas toujours affichées par défaut.

Ce qui était <div class="options-modal" ng-show="showOptions"></div>

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

avec le CSS pour la classe options-modal étant display: nonepar défaut. La classe show contient le display:blockCSS.

My Stack Overfloweth
la source
-2

Évitez les sauts de ligne

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

Fonctionne avec Firefox 45.0.1

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