231

I have an issue in angular.js with directive/class ng-cloak or ng-show.

Chrome works fine, but Firefox is causing blink of elements with ng-cloak or ng-show. IMHO it's caused by the converting ng-cloak/ng-show to style="display: none;", probably the Firefox javascript compiler is little bit slower, so the elements appears for a while and then hide?

Example:

<ul ng-show="foo != null" ng-cloak>..</ul>
rnrneverdies
  • 15,243
  • 9
  • 65
  • 95
MelkorNemesis
  • 3,415
  • 2
  • 20
  • 20
  • 1
    if you set display:none style on these elements initially, does it fix the problem? – akonsu Jun 28 '12 at 17:33
  • 3
    I will try that, i was trying something similar with adding class (which hides the element) and then removing it via js manually, but it looked even more bad. – MelkorNemesis Jun 28 '12 at 17:41

29 Answers29

388

Though the documentation doesn't mention it, it might not be enough to add the display: none; rule to your CSS. In cases where you are loading angular.js in the body or templates aren't compiled soon enough, use the ng-cloak directive and include the following in your 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;
}

As mentioned in the comment, the !important is important. For example, if you have the following markup

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

and you happen to be using bootstrap.css, the following selector is more specific for your ng-cloak'ed element

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

So if you include a rule with simply display: none;, Bootstrap's rule will take precedence and the display will be set to block, so you'll see the flicker before the template compiles.

Tim Schaub
  • 6,722
  • 1
  • 26
  • 17
  • 4
    Also note that this same issue can happen if you are loading angular.js using an asynchronous loader, such as require.js, because the css rule in the .js will not have been parsed in time. The solution above fixes this scenario as well. – Johann Jan 14 '13 at 15:51
  • 84
    Does't fix the issue for me. Don't know - I think the browsers are too eager to show things initially... – Andriy Drozdyuk Apr 01 '13 at 20:33
  • 7
    The browser should NEVER render the DOM without taking the css into account, even on the first pass; that would be highly inefficient; Double check your setup :p – AlexG Jul 15 '13 at 07:10
  • 1
    how do you re-bootstrap dom that has been ng-cloaked, once you lazy load that doms module code? – FutuToad Jun 18 '14 at 12:41
  • If the above css is not working for you chances are your `:` in `ng:cloak` is not escaped properly. For pure CSS make sure the backslash is there. For compiled css, e.g. Stylus, it will be `[ng\\:cloak]`. Check your compiled CSS to make sure it is correct. – Joe Feb 16 '15 at 16:24
  • Also add, you can't use ngCloak as data attribute , it just won't work. – Quijote Shin Apr 24 '15 at 16:00
  • In my case I also had to link my stylesheets before angular.js. – eskalera Jul 30 '15 at 12:30
  • If still not working in Firefox, but works in Chrome then look at [my answear](http://stackoverflow.com/a/35646736/1457197) about turning off the Firebug plugin. – CoperNick Jun 01 '16 at 06:56
  • Does not work on chrome either. My solution was to add the display: none !important; directly inline to the element, then in my controller when everything gets loaded, changed it display: block with jQuery. – Jon Crawford Jun 05 '16 at 09:46
  • The above didn't work for me at first because I was including my css via a compilation step with webpack. After directly inlining the above css into my index.html file it worked like a charm. – David Simic Jul 13 '17 at 19:13
47

As mentioned in the documentation, you should add a rule to your CSS to hide it based on the ng-cloak attribute:

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

We use similar tricks on the "Built with Angular" site, which you can view the source of on Github: https://github.com/angular/builtwith.angularjs.org

Hope that helps!

Rob Johansen
  • 5,076
  • 10
  • 40
  • 72
btford
  • 5,631
  • 2
  • 29
  • 26
  • 4
    angular.js adds that style rule to the head of the document. You really should not need to add this to your CSS. That said, this seems to work. My guess is because angular.js doesn't add the style block to the head until after loading angular. – ntownsend Dec 28 '12 at 00:29
  • 14
    What's *really* mentioned in the documentation is this: "For the best result, angular.js script must be loaded in the head section of the html file; **alternatively**, the css rule (above) must be included in the external stylesheet of the application." – Andriy Drozdyuk Apr 01 '13 at 20:31
  • 4
    In other words, if you're adding your script references at the bottom of your page (as a lot of people do); then add the rule to your CSS. – GFoley83 Apr 30 '13 at 04:54
  • 1
    I was adding angular.js with require.js, so this helped me. – olive Sep 09 '13 at 12:12
  • 1
    Added the ng-cloak directive to the html element housing the ng-app directive. Worked like a charm. Example:
    – miniscem Aug 01 '16 at 23:12
  • This is the best way to go. I had flicker even with the ng-hide method as I was using a transition effect, this solved it anyway. – edencorbin Jan 06 '17 at 17:32
  • @drozzy - your answer should be the accepted answer. thanks alot – nadav Feb 06 '17 at 09:21
33

Make sure AngularJS is included in the head of the HTML. See ngCloak doc:

For the best result, angular.js script must be loaded in the head section of the html file; alternatively, the css rule (above) must be included in the external stylesheet of the application.

Andriy Drozdyuk
  • 58,435
  • 50
  • 171
  • 272
  • 3
    yes! I can't understand why people everywhere seems to recommend loading angular.js at the end of the page. I feel better if Angular takes control right from the beginning. My `ng-cloak` is working now. – Ivan Ferrer Villa Mar 30 '15 at 15:27
  • 2
    I agree - the thing about scripts being loaded at the end comes from normal web development where you want the page to display something before the js does its thing, but in the case of angular, you actually want the reverse. – see sharper Aug 26 '15 at 03:26
  • 1
    AND before any style sheets are loaded. Including Angular in the `head` but after style sheet includes, doesn't fix the issue. – AgmLauncher Jun 02 '16 at 04:03
27

I've never had much luck using ngCloak. I still get flickering despite everything mentioned above. The only surefire way to avoid flicking is to put your content in a template and include the template. In a SPA, the only HTML that will get evaluated before being compiled by Angular is your main index.html page.

Just take everything inside the body and stick it in a separate file and then:

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

You should never get any flickering that way as Angular will compile the template before adding it to the DOM.

Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
Matt Hughes
  • 1,458
  • 2
  • 14
  • 17
  • 1
    Exactly what I use - clean and simple, no painful hacks. – Dmitri Zaitsev Aug 06 '14 at 09:58
  • 2
    Please be aware that `ng-include` spawns an additional AJAX request to fetch the content from the server. I learned the hard way that you should never use `ng-include` inside `ng-repeat`, for example. – jsuddsjr Oct 17 '14 at 14:37
  • 1
    worked for me. remember to keep `ng-app` outside of the `ng-include` in your markup. – GraehamF Mar 14 '15 at 19:03
  • 1
    Exactly, this is the only one that worked for me. Ng-cloak seems to improve things, but still find flickering behaviour on some templates. After long research, doing includes with ng-ifs has been the only reliable way, as in `
    `
    – danivicario Jun 25 '15 at 16:35
  • 2
    This solution works best, without any hiccups. If feasible, use this solution. – idungotnosn Jul 01 '15 at 15:00
  • 2
    This solution fixed a really annoying situation. Thank you! – Maxwelll Feb 19 '16 at 01:47
  • 1
    Tried ng-cloak solutions and they didn't work very well in my situation. But this technique worked perfect. – Greg Mar 18 '16 at 00:52
  • 1
    This fixed mine too. Thanks – manutdfan Nov 04 '16 at 17:13
22

ngBind and ngBindTemplate are alternatives that do not require 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
  • 362,217
  • 114
  • 495
  • 492
  • 1
    Nice, simple answer. `ng-bind` is a good way of avoiding the 'curly brace flash' or having to use `ng-cloak` at a tag level, although some people think it makes the code less readable. For them, I don't see a reason not to mix the two approaches. – Dave Everitt Nov 03 '13 at 08:34
  • 1
    ng-bind is much better approach to the problem as the other answers require you to load first angular, no curly braces flash at all in any circumstance – legramira Dec 15 '15 at 07:10
20

In addition to the accepted answer if you're using an alternative method of triggering ng-cloak...

You may also wish to add some additional specificities to your CSS/LESS:

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide {
    display: none !important;
}
Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
Corey Ballou
  • 42,389
  • 8
  • 62
  • 75
15

I had a similar issue and found out that if you have a class that contains transitions, the element will blink. I tried to add ng-cloak without success, but by removing the transition the button stopped blinking.

I'm using ionic framework and the button-outline has this transition

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

Simply overwrite the class to remove the transition and the button will stop blinking.

Update

Again on ionic there is a flicker when using ng-show/ng-hide. Adding the following CSS resolves it:

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

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

Seb Fanals
  • 645
  • 1
  • 6
  • 14
9

I had a problem where a <div ng-show="expression"> would be initially visible for a fraction of a second, even though "expression" was initially false, before the ng-show directive got a chance to run.

The solution I used was to manually add the "ng-hide" class, as in <div ng-show="expression" ng-hide>, to make sure it started initially hidden. The ng-show directive will add/remove the ng-hide class as necessary after that.

metamatt
  • 13,809
  • 7
  • 46
  • 56
7

Try to turn off the Firebug. I'm serious. This helps in my case.

Apply accepted answer and then make sure that Firebug in your Firefox is turned off: press F12 then turn off Firebug for this page - small button in upper right corner.

CoperNick
  • 2,413
  • 2
  • 21
  • 26
6

There's actually two separate problems that can cause the flicker issue and you could be facing either one or both of these.

Problem 1: ng-cloak is applied too late

This issue is solved as descibed in many of the answers on this page is to make sure AngularJS is loaded in the head. See ngCloak doc:

For the best result, angular.js script must be loaded in the head section of the html file; alternatively, the css rule (above) must be included in the external stylesheet of the application.

Problem 2: ng-cloak is removed too soon

This issue is most likely to occur when you have a lot of CSS on your page with rules cascading over one another and the deeper layers of CSS flash up before the top layer is applied.

The jQuery solutions in answers involving adding style="display:none" to your element do solve this issue so long as the style is removed late enough (in fact these solutions solve both problems). However, if you prefer not to add styles directly to your HTML you can achieve the same results using ng-show.

Starting with the example from the question:

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

Add an additional ng-show rule to your element:

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

(You need to keep ng-cloak to avoid problem 1).

Then in your app.run set isPageFullyLoaded:

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

Be aware that depending on exactly what you're doing, app.run may or may not be the best place to set isPageFullyLoaded. The important thing is to make sure that isPageFullyLoaded gets set to true after whatever it is you don't want to flicker is ready to be revealed to the user.

It sounds like Problem 1 is the problem the OP is hitting, but others are finding that solution does not work or only partially works because they are hitting Problem 2 instead or as well.

Important Note: Be sure to apply solutions to both ng-cloak being applied too late AND removed to soon. Solving only one of these problems may not relieve the symptoms.

Andrew Downes
  • 1,068
  • 8
  • 20
4

We ran into this problem at our company and solved it by adding "display: none" to the CSS styling for those flickering ng-show elements. We didn't have to use ng-cloak at all. Unlike others in this thread, we experienced this issue in Safari but not Firefox or Chrome -- possibly due to Safari's lazy repaint bug in iOS7.

Jake McGuire
  • 304
  • 2
  • 4
3

For what it's worth, I had a similar issue ng-cloak not working. It may be worth checking your app/site with cache enabled to reuse source files to see if that helps.

With my run-in with flickering, I was testing with DevTools open and cache disabled. Leaving the panel closed with caching enabled fixed my issue.

mrdazm
  • 31
  • 1
3

Keeping the below statements in head tag fixed this issue

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

official documentation

Saikiran Komirishetty
  • 6,525
  • 1
  • 29
  • 36
3

I couldn't get any of these methods to work, so I eventually did the following. For the element you want initially hidden:

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

Then in your controller, add this at or near the top:

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

This way, the element is initially hidden, and only shows when the controller code has actually run.

You can tune the placement to your needs, perhaps adding some logic. In my case, I switch to a login path if not currently logged in, and didn't want my interface flickering beforehand, so I set $scope.style after the logged-in check.

shawkinaw
  • 3,190
  • 2
  • 27
  • 30
2

It's better to use ng-if instead of ng-show. ng-if completely removes and recreates the element in the DOM and helps to avoid ng-shows blinking.

alexey
  • 783
  • 1
  • 7
  • 19
2

I'm using ionic framework, adding css style might not work for certain circumstances, you can try using ng-if instead of ng-show / ng-hide

ref: https://books.google.com.my/books?id=-_5_CwAAQBAJ&pg=PA138&lpg=PA138&dq=ng-show+hide+flickering+in+ios&source=bl&ots=m2Turk8DFh&sig=8hNiWx26euGR2k_WeyaVzdixJ8k&hl=en&sa=X&redir_esc=y#v=onepage&q=ng-show%20hide%20flickering%20in%20ios&f=false

d1ck50n
  • 1,331
  • 2
  • 16
  • 20
2

you'd better reference angular document, becuase the version[1.4.9] has update to below that make it could support data-ng-cloak directive.

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

I tried the ng-cloak solution above but it still has intermittent issues with Firefox. The only workaround that worked for me is to delay the loading of the form until Angular is fully loaded.

I simply added ng-init in the app and use ng-if at the form side to check if the variable I set is already loaded.

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

In addition to other answers, if you find the flash of template code to still be occuring it is likely you have your scripts at the bottom of the page and that means that the ng-cloak directive straight up will not work. You can either move your scripts to the head or create a CSS rule.

The docs say "For the best result, the angular.js script must be loaded in the head section of the html document; alternatively, the css rule above must be included in the external stylesheet of the application."

Now, it doesn't have to be an external stylesheet but just in a element in the head.

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

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

Elijah Lynn
  • 12,272
  • 10
  • 61
  • 91
1

I tried every solution posted here and still got flickering in Firefox.

If it helps anyone, I solved it by adding style="display: none;" to the main content div, then using jQuery (I was already using it on the page) $('#main-div-id').show(); once everything was loaded after getting data from the server;

hipnosis
  • 618
  • 1
  • 8
  • 13
  • I found this was the only solution that worked for me, but I wanted to avoid using JQuery so found an alternative. See my answer here: http://stackoverflow.com/a/42527700/4214694 – Andrew Downes Mar 01 '17 at 09:21
1

I actually found the suggestion from Rick Strahl's Web Log fixed my issue perfectly (as I still had the odd issue with ng-cloak blinking raw {{code}} at times, especially while running Firebug):

The nuclear option: Hiding the Content manually

Using the explicit CSS is the best choice, so the following shouldn’t ever be necessary. But I’ll mention it here as it gives some insight how you can hide/show content manually on load for other frameworks or in your own markup based templates.

Before I figured out that I could explicitly embed the CSS style into the page, I had tried to figure out why ng-cloak wasn’t doing its job. After wasting an hour getting nowhere I finally decided to just manually hide and show the container. The idea is simple – initially hide the container, then show it once Angular has done its initial processing and removal of the template markup from the page.

You can manually hide the content and make it visible after Angular has gotten control. To do this I used:

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

Notice the display: none style that explicitly hides the element initially on the page.

Then once Angular has run its initialization and effectively processed the template markup on the page you can show the content. For Angular this ‘ready’ event is the app.run() function:

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

This effectively removes the display:none style and the content displays. By the time app.run() fires the DOM is ready to displayed with filled data or at least empty data – Angular has gotten control.

Campbeln
  • 2,880
  • 3
  • 33
  • 33
  • I found this was the only solution that worked for me, but I wanted to avoid using JQuery so found an alternative. See my answer here: http://stackoverflow.com/a/42527700/4214694 – Andrew Downes Mar 01 '17 at 09:19
1

I tried all of the answers above and nothing worked. Using ionic to develop a hybrid app and was trying to make an error message not flicker. I ended up solving my issue by adding an ng-hide class to my element. My div already has ng-show to show the element when there is an error. Adding ng-hide set the div to not display before angular is loaded. No ng-cloak or adding angular to the head necessary.

gyleg5
  • 144
  • 1
  • 2
  • 11
1

AS from the above discussion

[ng-cloak] {
                display: none;
            }

is the perfect way to solve the Problem.

Dinesh Jain
  • 149
  • 11
1

I'm using ng-show in a directive to show and hide popups.

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

None of the above worked for me, and using ng-if instead of ng-show would be an overkill. That would imply removing and adding the whole popup content into the DOM at every single click. Instead I added an ng-if into the same element to make sure it doesn't show at the document load:

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

Afterwards I added the initialization into the controller responsible of this directive with a timeout:

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

This way I eliminated the flickering issue and avoided the costly operation of DOM insertion at every single click. This came at an expense of using two scope variables for the same purpose instead of one, but so far this is definitely the best option.

downhand
  • 395
  • 1
  • 9
  • 23
1

Tried ng-cloak but still brief blinks. Below code rid them completely.

<body style="display:none;" ng-style="{'display':'block'}">
Abu Abdullah
  • 4,004
  • 1
  • 17
  • 15
1

None of the solutions listed above worked for me. I then decided to look at the actual function and realised that when “$scope.watch ” was fired, it was putting a value in the name field which was not meant to be the case. So in the code I set and oldValue and newValue then

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

Essentially when scope.watch is fired in this case, AngularJS monitors the changes to the name variable (model.value)

D.Adelakun
  • 11
  • 2
0

I would would wrap the <ul> with a <div ng-cloak>

Taryn
  • 242,637
  • 56
  • 362
  • 405
Dan Doyon
  • 6,710
  • 2
  • 31
  • 40
  • 2
    He shouldn't need to wrap the `
      `. `ng-cloak` will cloak whichever element it's applied to, as well as the descendants of that element.
    – btford Jun 29 '12 at 09:21
0

I personally decided to use the ng-class attribute rather than the ng-show. I've had a lot more success going this route especially for pop-up windows that are always not shown by default.

What used to be <div class="options-modal" ng-show="showOptions"></div>

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

with the CSS for the options-modal class being display: none by default. The show class contains the display:block CSS.

My Stack Overfloweth
  • 4,729
  • 4
  • 25
  • 42
-2

Avoid line break

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

Works with Firefox 45.0.1

<meta http-equiv="Content-Security-Policy"              content="    default-src 'FOO';    script-src 'FOO';     style-src  'FOO';    font-src 'FOO';">
Chris Stillwell
  • 10,266
  • 10
  • 67
  • 77
Espigah
  • 1
  • 1