Angularjs - elementy ng-cloak / ng-show migają


231

Mam problem w angular.js z dyrektywą / klasą ng-cloaklub ng-show.

Chrome działa dobrze, ale Firefox powoduje miganie elementów za pomocą ng-cloaklub ng-show. IMHO jest spowodowany przez konwersję ng-cloak/ ng-showdo style="display: none;", prawdopodobnie kompilator javascript w Firefoksie jest nieco wolniejszy, więc elementy pojawiają się przez chwilę, a następnie się chowają?

Przykład:

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

1
jeśli ustawisz display: żaden styl na tych elementach na początku, czy to rozwiąże problem?
akonsu

3
Spróbuję tego, próbowałem czegoś podobnego z dodaniem klasy (która ukrywa element), a następnie ręcznym usunięciem za pomocą js, ale wyglądało to jeszcze gorzej.
MelkorNemesis

Odpowiedzi:


385

Chociaż dokumentacja nie wspomina o tym, dodanie display: none;reguły do ​​CSS może być niewystarczające . W przypadku, gdy ładujesz plik angular.js w treści lub szablony nie są wystarczająco szybko skompilowane, skorzystaj z ng-cloakdyrektywy i dołącz do 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;
}

Jak wspomniano w komentarzu, !importantjest to ważne. Na przykład, jeśli masz następujące znaczniki

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

i akurat używasz bootstrap.css, poniższy selektor jest bardziej szczegółowy dla twojego ng-cloakelementu ed

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

Jeśli więc włączysz regułę po prostu display: none;, reguła Bootstrap będzie miała pierwszeństwo i displayzostanie ustawiona na block, więc zobaczysz migotanie przed kompilacją szablonu.


3
Należy również pamiętać, że ten sam problem może wystąpić, jeśli ładujesz plik angular.js przy użyciu asynchronicznego programu ładującego, takiego jak wymagany.js, ponieważ reguła css w pliku .js nie zostanie przeanalizowana na czas. Powyższe rozwiązanie naprawia również ten scenariusz.
Johann

84
Dla mnie to nie rozwiązuje problemu. Nie wiem - myślę, że przeglądarki są zbyt chętne, aby początkowo pokazywać
różne

7
Przeglądarka NIGDY nie powinna renderować DOM bez uwzględnienia css, nawet przy pierwszym przejściu; byłoby to wysoce nieefektywne; Sprawdź
dokładnie

1
Jak ponownie załadować dom, który został zamaskowany przez Ng, gdy leniwie załadujesz kod modułu Doms?
FutuToad

Jeśli powyższe css nie pracuje dla was są szanse :na ng:cloaknie uciekł prawidłowo. Dla czystego CSS upewnij się, że występuje odwrotny ukośnik. Dla skompilowanego css, np. Stylus, będzie [ng\\:cloak]. Sprawdź skompilowany CSS, aby upewnić się, że jest poprawny.
Joe

47

Jak wspomniano w dokumentacji , należy dodać regułę do CSS, aby ukryć ją na podstawie ng-cloakatrybutu:

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

Podobne sztuczki wykorzystujemy na stronie „Built with Angular”, której źródło możesz obejrzeć na Github: https://github.com/angular/builtwith.angularjs.org

Mam nadzieję, że to pomaga!


4
angular.js dodaje tę regułę stylu do nagłówka dokumentu. Naprawdę nie powinieneś dodawać tego do swojego CSS. To powiedziawszy, to wydaje się działać. Sądzę, że angular.js nie dodaje bloku stylu do głowy, dopóki nie załaduje angulara.
ntownsend

13
W dokumentacji tak naprawdę wspomniano: „Aby uzyskać najlepszy wynik, skrypt angular.js musi zostać załadowany do sekcji head pliku HTML; alternatywnie reguła css (powyżej) musi być zawarta w zewnętrznym arkuszu stylów aplikacji. „
Andriy Drozdyuk

4
Innymi słowy, jeśli dodajesz odwołania do skryptu na dole strony (jak robi to wiele osób); następnie dodaj regułę do swojego CSS.
GFoley83

1
Dodałem plik angular.js z wymaganiem.js, więc to mi pomogło.
oliwka

1
Dodano dyrektywę ng-cloak do elementu HTML zawierającego dyrektywę ng-app. Działa jak urok. Przykład: <div ng-cloak ng-app = "my-app">
miniscem

33

Upewnij się, że AngularJS znajduje się w kodzie headHTML. Zobacz dokument ngCloak :

Aby uzyskać najlepszy wynik, skrypt angular.js musi zostać załadowany w sekcji head pliku HTML; alternatywnie reguła css (powyżej) musi być zawarta w zewnętrznym arkuszu stylów aplikacji.


3
tak! Nie rozumiem, dlaczego ludzie na całym świecie zalecają ładowanie pliku angular.js na końcu strony. Czuję się lepiej, jeśli Angular przejmie kontrolę od samego początku. Mój ng-cloakteraz pracuje.
Ivan Ferrer Villa

2
Zgadzam się - problem z ładowaniem skryptów na końcu pochodzi z normalnego tworzenia stron internetowych, gdzie chcesz, aby strona wyświetlała coś, zanim js zrobi swoje, ale w przypadku angulara, naprawdę chcesz odwrotnie.
patrz ostrzejszy

1
ORAZ przed załadowaniem jakichkolwiek arkuszy stylów. Włączenie Angulara do headarkusza stylów późniejszych nie rozwiązuje problemu.
AgmLauncher

27

Nigdy nie miałem dużo szczęścia, używając ngCloak. Nadal migoczę pomimo wszystkiego, co wspomniano powyżej. Jedynym pewnym sposobem na uniknięcie przesuwania jest umieszczenie treści w szablonie i dołączenie szablonu. W SPA jedynym HTMLem, który zostanie oceniony przed kompilacją przez Angular, jest twoja główna strona index.html.

Po prostu weź wszystko do ciała i umieść w osobnym pliku, a następnie:

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

Nigdy nie powinieneś migotać w ten sposób, ponieważ Angular skompiluje szablon przed dodaniem go do DOM.


1
Dokładnie to, czego używam - czyste i proste, bez bolesnych hacków.
Dmitri Zaitsev,

2
Należy pamiętać, że ng-includespawnuje dodatkowe żądanie AJAX w celu pobrania zawartości z serwera. Nauczyłem się na przykład, że nigdy nie powinieneś używać w ng-includeśrodku ng-repeat.
jsuddsjr

1
pracował dla mnie. pamiętaj, aby trzymać się ng-apppoza ng-includeznacznikami.
GraehamF,

2
To rozwiązanie działa najlepiej, bez żadnych czkawek. Jeśli to możliwe, skorzystaj z tego rozwiązania.
idungotnosn

2
To rozwiązanie naprawiło irytującą sytuację. Dziękuję Ci!
Maxwelll,

22

ngBind i ngBindTemplate to alternatywy, które nie wymagają 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>

1
Ładna, prosta odpowiedź. ng-bindto dobry sposób na uniknięcie „flashowania nawiasami klamrowymi” lub konieczności używania go ng-cloakna poziomie tagów, chociaż niektórzy uważają, że sprawia, że ​​kod jest mniej czytelny. Dla nich nie widzę powodu, aby nie mieszać tych dwóch podejść.
Dave Everitt

1
ng-wiążą jest znacznie lepsze podejście do problemu, jak inne odpowiedzi wymaga, aby załadować pierwszy kątowe, nie ma nawiasy klamrowe migać w ogóle w żadnym wypadku
legramira

20

Oprócz zaakceptowanej odpowiedzi, jeśli używasz alternatywnej metody wyzwalania ng-cloak ...

Możesz również dodać kilka dodatkowych szczegółów do swojego CSS / MNIEJ:

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

1
To zadziałało w moim przypadku użycia, gdy żadne z powyższych nie wydawało się wykonać zadania.
Porlune

15

Miałem podobny problem i odkryłem, że jeśli masz klasę zawierającą przejścia, element będzie migał. Próbowałem dodać ng-cloak bez powodzenia, ale po usunięciu przejścia przycisk przestał migać.

Używam szkieletu jonowego, a kontur przycisku ma to przejście

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

Wystarczy zastąpić klasę, aby usunąć przejście, a przycisk przestanie migać.

Aktualizacja

Ponownie na jonach pojawia się migotanie podczas używania ng-show / ng-hide. Dodanie następującego CSS rozwiązuje to:

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

Źródło: http://forum.ionicframework.com/t/beta-14-ng-hide-show/14270/9


1
Ale czy nie wyłączałoby to animacji dla dyrektyw ng-hide / show?
Kushagra Gour

1
Nie pamiętam Próbowałeś i to wyłączyło animacje?
Seb Fanals

1
Dzięki. Jest to bardzo szczególny problem z jonami. Dodałem .button-clear, .button-icon, .button-outline { @include transition(opacity 0s); }do mojego scss.
hgoebl

9

Miałem problem polegający na tym, <div ng-show="expression">że na początku ułamek sekundy byłby widoczny, chociaż „wyrażenie” było początkowo fałszywe, zanim dyrektywa ng-show miała szansę uruchomić.

Rozwiązaniem, którego użyłem było ręczne dodanie klasy „ng-hide”, tak jak w <div ng-show="expression" ng-hide>, aby upewnić się, że początkowo była ukryta. Dyrektywa ng-show w razie potrzeby doda / usunie klasę ng-hide.


1
wow, ze wszystkich dziwnych opcji, które wypróbowałem, to załatwiło sprawę. Dziękuję Ci!
Nikola

Najlepsze rozwiązanie! Doprowadzało mnie to do szaleństwa przez kilka miesięcy! Dziękuję Ci!
abelabbesnabi

Używam szkieletu jonowego i jest to jedyna odpowiedź, która faktycznie działa
Mikel

7

Spróbuj wyłączyć Firebug . Jestem poważny. To pomaga w moim przypadku.

Zastosuj zaakceptowaną odpowiedź, a następnie upewnij się, że Firebug w przeglądarce Firefox jest wyłączony : naciśnij F12, a następnie wyłącz Firebug dla tej strony - mały przycisk w prawym górnym rogu.


Tak, zrobiłem to dla mnie Dzięki!
MadeInDreams

Dziękuję, to doprowadzało mnie do szału. Dziwny błąd
Stephen Simpson

6

W rzeczywistości istnieją dwa oddzielne problemy, które mogą powodować problem z migotaniem i możesz napotkać jeden lub oba z nich.

Problem 1: Płaszcz ng nakłada się zbyt późno

Ten problem został rozwiązany, jak opisano w wielu odpowiedziach na tej stronie, aby upewnić się, że AngularJS jest załadowany do głowy. Zobacz dokument ngCloak :

Aby uzyskać najlepszy wynik, skrypt angular.js musi zostać załadowany w sekcji head pliku HTML; alternatywnie reguła css (powyżej) musi być zawarta w zewnętrznym arkuszu stylów aplikacji.

Problem 2: Płaszcz ng jest usuwany zbyt wcześnie

Ten problem występuje najprawdopodobniej, gdy na stronie jest dużo CSS z regułami kaskadowymi względem siebie, a głębsze warstwy CSS migają przed nałożeniem górnej warstwy.

Rozwiązania jQuery w odpowiedziach dotyczących dodawania style="display:none"do elementu rozwiązują ten problem, o ile styl jest usuwany wystarczająco późno (w rzeczywistości rozwiązania te rozwiązują oba problemy). Jeśli jednak wolisz nie dodawać stylów bezpośrednio do kodu HTML, możesz osiągnąć te same wyniki za pomocą ng-show.

Począwszy od przykładu z pytania:

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

Dodaj dodatkową regułę ng-show do swojego elementu:

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

(Musisz zachować, ng-cloakaby uniknąć problemu 1).

Następnie w zestawie aplikacji. Uruchom isPageFullyLoaded:

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

Pamiętaj, że w zależności od tego, co robisz, app.run może być najlepszym miejscem do ustawienia isPageFullyLoaded. Ważne jest, aby upewnić się, że isPageFullyLoadedzostanie ustawiona wartość true, gdy wszystko, czego nie chcesz migotać, jest gotowe do ujawnienia użytkownikowi.

Wygląda na to, że Problem 1 jest problemem, na który uderza OP, ale inni stwierdzają, że rozwiązanie nie działa lub tylko częściowo działa, ponieważ zamiast tego trafia na Problem 2 lub też.

Ważna uwaga: pamiętaj, aby zastosować rozwiązania na obu płaszczach ng nakładanych zbyt późno ORAZ usunąć je wkrótce. Rozwiązanie tylko jednego z tych problemów może nie złagodzić objawów.


1
to naprawiło to dla mnie „skrypt musi być załadowany w sekcji nagłówka”
aliopi

4

W naszej firmie napotkaliśmy ten problem i rozwiązaliśmy go, dodając „display: none” do stylizacji CSS dla tych migających elementów ng-show. W ogóle nie musieliśmy używać peleryny. W przeciwieństwie do innych w tym wątku ten problem występował w przeglądarce Safari, ale nie w przeglądarce Firefox ani Chrome - prawdopodobnie z powodu leniwego błędu odświeżania przeglądarki Safari w systemie iOS7 .


3

Za to, co jest warte, miałem podobny problem z niedziałającym płaszczem ng. Warto sprawdzić swoją aplikację / witrynę z włączoną pamięcią podręczną, aby ponownie wykorzystać pliki źródłowe, aby sprawdzić, czy to pomoże.

Z moim docierania z migotaniem testowałem przy otwartym DevTools i wyłączonej pamięci podręcznej. Pozostawienie panelu zamkniętego z włączonym buforowaniem naprawiło mój problem.


3

Utrzymanie poniższych instrukcji w tagu head rozwiązało ten problem

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

oficjalna dokumentacja


3

Nie mogłem zmusić żadnej z tych metod do działania, więc w końcu zrobiłem następujące. W przypadku elementu, który chcesz początkowo ukryć:

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

Następnie w kontrolerze dodaj to na górze lub w pobliżu:

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

W ten sposób element jest początkowo ukryty i wyświetla się tylko wtedy, gdy kod kontrolera rzeczywiście się uruchomił.

Możesz dostosować miejsce docelowe do swoich potrzeb, być może dodając trochę logiki. W moim przypadku przełączam się na ścieżkę logowania, jeśli nie jestem zalogowany, i nie chciałem wcześniej migotać interfejsu, więc ustawiłem $scope.stylepo sprawdzeniu zalogowanego.


2

Lepiej używać ng-ifzamiast ng-show. ng-if całkowicie usuwa i odtwarza element w DOM i pomaga uniknąć mrugania na ng-show.


ale niszczy również wszelkie działające wtyczki w tej części domu ... (np. jquery ui)
Geert Bellemans


2

Lepiej odwołaj się do dokumentu kątowego, ponieważ wersja [1.4.9] ma aktualizację poniżej, dzięki czemu może obsługiwać dyrektywę maskowania danych.

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

2

Wypróbowałem powyższe rozwiązanie ng-cloak, ale nadal występują sporadyczne problemy z Firefoksem. Jedynym obejściem, które działało dla mnie, było opóźnienie ładowania formularza do momentu pełnego załadowania Angulara.

Po prostu dodałem ng-init w aplikacji i używam ng-if po stronie formularza, aby sprawdzić, czy ustawiona zmienna jest już załadowana.

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

1

Oprócz innych odpowiedzi, jeśli nadal pojawia się flash kodu szablonu, prawdopodobnie masz skrypty na dole strony, co oznacza, że ​​dyrektywa ng-cloak nie będzie działać. Możesz przenieść skrypty do głowy lub utworzyć regułę CSS.

Dokumenty mówią „Aby uzyskać najlepszy wynik, skrypt angular.js musi zostać załadowany w sekcji head dokumentu HTML; alternatywnie powyższa reguła css musi zostać zawarta w zewnętrznym arkuszu stylów aplikacji”.

Teraz nie musi to być zewnętrzny arkusz stylów, ale tylko element w głowie.

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

źródło: https://docs.angularjs.org/api/ng/directive/ngCloak


1

Wypróbowałem wszystkie zamieszczone tutaj rozwiązania i nadal migotałem w przeglądarce Firefox.

Jeśli komukolwiek to pomaga, rozwiązałem go, dodając style="display: none;"do głównego div div treści, a następnie używając jQuery (użyłem go już na stronie), $('#main-div-id').show();gdy wszystko zostało załadowane po pobraniu danych z serwera;


Odkryłem, że było to jedyne rozwiązanie, które działało dla mnie, ale chciałem uniknąć używania JQuery, więc znalazłem alternatywę. Zobacz moją odpowiedź tutaj: stackoverflow.com/a/42527700/4214694
Andrew Downes

1

Właściwie znalazłem sugestię z dziennika sieci Ricka Strahla doskonale rozwiązała mój problem (ponieważ wciąż miałem dziwny problem z czasami mruganiem surowego {{code}} ng-cloak, szczególnie podczas uruchamiania Firebug):

Opcja nuklearna: ręczne ukrywanie treści

Korzystanie z jawnego CSS jest najlepszym wyborem, więc poniższe nie powinny być nigdy konieczne. Ale wspomnę o tym tutaj, ponieważ daje pewien wgląd w to, jak ręcznie ukrywać / wyświetlać zawartość przy ładowaniu dla innych frameworków lub we własnych szablonach opartych na znacznikach.

Zanim zorientowałem się, że mogę wyraźnie osadzić styl CSS na stronie, próbowałem dowiedzieć się, dlaczego ng-cloak nie spełnia swojej roli. Po marnowaniu godziny na nic nie zdecydowałem w końcu po prostu ręcznie ukryć i pokazać pojemnik. Pomysł jest prosty - początkowo ukryj pojemnik, a następnie pokaż go, gdy Angular dokończy przetwarzania i usunie znaczniki szablonu ze strony.

Możesz ręcznie ukryć zawartość i sprawić, aby była widoczna po przejęciu kontroli przez Angular. Aby to zrobić, użyłem:

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

Zwróć uwagę na sposób wyświetlania: żaden styl, który początkowo wyraźnie ukrywa element na stronie.

Następnie, gdy Angular uruchomi swoją inicjalizację i efektywnie przetworzy znaczniki szablonów na stronie, możesz wyświetlić zawartość. W przypadku Angular tym „gotowym” zdarzeniem jest funkcja app.run ():

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

To skutecznie usuwa wyświetlanie: brak stylu i wyświetlanie zawartości. Do czasu uruchomienia app.run () DOM jest gotowy do wyświetlenia z wypełnionymi danymi lub przynajmniej pustymi danymi - Angular przejął kontrolę.


Odkryłem, że było to jedyne rozwiązanie, które działało dla mnie, ale chciałem uniknąć używania JQuery, więc znalazłem alternatywę. Zobacz moją odpowiedź tutaj: stackoverflow.com/a/42527700/4214694
Andrew Downes

1

Próbowałem wszystkich powyższych odpowiedzi i nic nie działało. Używałem jonu do opracowania aplikacji hybrydowej i starałem się, aby komunikat o błędzie nie migał. Rozwiązałem problem, dodając klasę ng-hide do mojego elementu. Mój div ma już ng-show, aby pokazać element, gdy wystąpi błąd. Dodanie ng-hide powoduje, że div nie będzie wyświetlany przed załadowaniem kąta. Nie jest konieczne maskowanie ani powiększanie głowy pod kątem.


1

AS z powyższej dyskusji

[ng-cloak] {
                display: none;
            }

to idealny sposób na rozwiązanie problemu.


1

Używam ng-show w dyrektywie, aby wyświetlać i ukrywać wyskakujące okienka.

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

Żadne z powyższych nie działało dla mnie, a użycie ng-if zamiast ng-show byłoby przesadą. Oznaczałoby to usunięcie i dodanie całej zawartości wyskakującego okienka do DOM za każdym kliknięciem. Zamiast tego dodałem ng-if do tego samego elementu, aby upewnić się, że nie wyświetla się przy ładowaniu dokumentu:

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

Następnie dodałem inicjalizację do kontrolera odpowiedzialnego za tę dyrektywę z limitem czasu:

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

W ten sposób wyeliminowałem problem migotania i uniknąłem kosztownej operacji wstawiania DOM przy każdym kliknięciu. Stało się to kosztem użycia dwóch zmiennych zasięgu w tym samym celu zamiast jednej, ale jak dotąd jest to zdecydowanie najlepsza opcja.


1

Próbowałem, ng-cloakale wciąż mruga. Poniższy kod pozbądź się ich całkowicie.

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

1

Żadne z wyżej wymienionych rozwiązań nie działało dla mnie. Następnie postanowiłem spojrzeć na faktyczną funkcję i zdałem sobie sprawę, że kiedy uruchomiono „$ scope.watch”, wstawiało wartość w polu nazwy, co nie miało tak być. Więc w kodzie ustawiłem i oldValue i newValue

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

Zasadniczo, gdy w tym przypadku zostanie uruchomiony zakres.watch, AngularJS monitoruje zmiany w zmiennej nazwy (model.value)


0

Chciałbym by owinąć <ul>z<div ng-cloak>


2
Nie powinien tego robić <ul>. ng-cloakbędzie maskować dowolny element, do którego jest zastosowany, a także potomków tego elementu.
btford

0

Ja osobiście zdecydowałem się użyć ng-classatrybutu zamiast ng-show. Odniosłem dużo większy sukces na tej trasie, szczególnie w przypadku okien wyskakujących, które zawsze nie są wyświetlane domyślnie.

Co było kiedyś <div class="options-modal" ng-show="showOptions"></div>

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

display: nonedomyślnie CSS dla klasy modów opcji . Klasa show zawiera display:blockCSS.


-2

Unikaj łamania linii

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

Działa z Firefoksem 45.0.1

<meta http-equiv="Content-Security-Policy"              content="    default-src 'FOO';    script-src 'FOO';     style-src  'FOO';    font-src 'FOO';">
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.