299

It seems to be primarily an issue in IE when there is a number of images/scripts to load, there can be a good amount of time where the literal {{stringExpression}} in the markup are displayed, then disappear once angular is done with it's compilation/interpolation of the document.

Is there a common reason why this would happen which would indicate I'm doing something generally wrong, or is there a known way to prevent this?

JeremyWeir
  • 24,118
  • 10
  • 92
  • 107

7 Answers7

284

I think that you are looking for the ngCloak directive: https://docs.angularjs.org/api/ng/directive/ngCloak

From the documentation:

The ngCloak directive is used to prevent the Angular html template from being briefly displayed by the browser in its raw (uncompiled) form while your application is loading. Use this directive to avoid the undesirable flicker effect caused by the html template display.

The directive can be applied to the <body> element, but the preferred usage is to apply multiple ngCloak directives to small portions of the page to permit progressive rendering of the browser view

Community
  • 1
  • 1
pkozlowski.opensource
  • 117,202
  • 60
  • 326
  • 286
199

Also, you can use <span ng-bind="hello"></span> instead of {{hello}}.

http://jsfiddle.net/4LhN9/34/

Andrew Joslin
  • 43,033
  • 21
  • 100
  • 75
  • 95
    One feature about ng-bind that is sometimes overlooked is that you can specify text to display while Angular is loading: loading.... "loading..." will appear, then be replaced once myScopeProperty is defined. – Mark Rajcok Oct 13 '12 at 04:23
  • @MarkRajcok: thanks for the tip! I had no idea. That's very simple and elegant and solves a problem I myself have had. – Jim Raden Oct 13 '12 at 19:54
  • 9
    If you need multiple expressions, use ngBindTemplate. E.g., loading... – Mark Rajcok Oct 13 '12 at 21:25
  • 27
    You can also do {{hello || 'loading...'}} – Andrew Joslin Oct 13 '12 at 21:40
  • 5
    @AndyJoslin Nice. With this approach, the angular js script needs to be in the head, as opposed to the bottom of the page, to avoid the {{}} expression from flashing when the page loads. – s_t_e_v_e Jul 11 '13 at 22:52
  • using ng-bind fixed it for me http://branchandbound.net/blog/web/2013/08/some-angularjs-pitfalls/ – Edmund Rojas Jan 07 '16 at 12:54
  • {{hello || 'loading...'}} is bad idea. Because if you want to show some some elements bound with flag in ng-controller that all elements will show and the ui will be a mess. The only solution is ng-cloak. You do not need css in the latest angularjs version. – Sahib Khan Nov 15 '16 at 04:32
  • Also binding is not a good idea in case you have large code, then you will need to update all those from {{}} to ng-bind – Sahib Khan Nov 15 '16 at 04:33
  • This i believe is the real answer! – Muhammad bin Yusrat Jan 21 '17 at 03:50
  • I thank you a ton! This is helpful for me since I am trying to use Angular Page with backend consisting of Django only, and Django takes such {{ ... }} angular elements as its own, which messes up everything. – Kartikeya Jun 09 '21 at 07:14
51

To improve the effectiveness of class='ng-cloak' approach when scripts are loaded last, make sure the following css is loaded in the head of the document:

.ng-cloak { display:none; }
LOAS
  • 7,161
  • 2
  • 28
  • 25
  • 4
    Adding !important is not bad idea also. – eomeroff Dec 13 '13 at 15:28
  • 12
    Wouldn't `visibility: hidden` be better? – mpen Dec 14 '13 at 08:50
  • 2
    @eomeroff, but `!important` is a CSS **hack** (bad thing) to promote a style to be selected, right? It breaks the CSS selector rules. – Kevin Meredith Jan 03 '14 at 02:37
  • 5
    IMHO this is one of the cases !important was introduced for. – lex82 Feb 09 '14 at 14:35
  • 3
    @Mark I would guess that "visibility: hidden" would still render the space needed for the template markup, whereas "display:none" doesn't render anything at all. With only the visibility hidden, any outer elements may suddenly collapse to the true inner size, instead of growing to size from nothing. I suppose it's whatever one prefers. :) – James Wilkins Mar 26 '14 at 00:41
  • @JamesWilkins: Yeah..you're right. I might not have been thinking about the size difference when I wrote that. – mpen Mar 26 '14 at 15:46
  • visibility vs display is just a matter of preference. Try them both! – trusktr May 07 '14 at 18:48
  • @JamesWilkins visibility: hidden or display: none are both good options, and depends on the goal -- if the goal is to preserve the document's structure then visibility:hidden works well, otherwise display:none does the trick. – mjwunderlich Feb 26 '15 at 02:02
  • 1
    @MJWunderlich : As I stated, "it's whatever one prefers.", so you're just rewording what I said. :P ;) – James Wilkins Feb 27 '15 at 03:51
  • @JamesWilkins I reworded & expanded to clarify. – mjwunderlich Feb 27 '15 at 12:48
  • @MJWunderlich : for who, me? (since you tagged my name) lol. ;) IMHO I think I was nore detailed and clear, but to each his own I guess. :P – James Wilkins Feb 27 '15 at 18:50
40

Just add the cloaking CSS to the head of the page or to one of your CSS files:

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

Then you can use the ngCloak directive according to normal Angular practice, and it will work even before Angular itself is loaded.

This is exactly what Angular does: the code at the end of angular.js adds the above CSS rules to the head of the page.

Bennett McElwee
  • 24,740
  • 6
  • 54
  • 63
21

In your css add folllowing

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

And then in you code you can add ng-cloak directive. For example,

<div ng-cloak>
   Welcome {{data.name}}
</div>

Thats it!

6

You also can use ng-attr-src="{{variable}}" instead of src="{{variable}}" and the attribute will only be generated once the compiler compiled the templates. This is mentioned here in the documentation: https://docs.angularjs.org/guide/directive#-ngattr-attribute-bindings

Martin Schüller
  • 904
  • 1
  • 9
  • 7
3

I agree with @pkozlowski.opensource answer, but ng-clock class did't work for me for using with ng-repeat. so I would like to recommend you to use class for simple delimiter expression like {{name}} and ngCloak directive for ng-repeat.

<div class="ng-cloak">{{name}}<div>

and

<li ng-repeat="item in items" ng-cloak>{{item.name}}<li>
Jaison James
  • 4,414
  • 4
  • 42
  • 54