66

Somehow, ng-cloak in AngularJS doesn't work. I want to hide {{ }} while loading the page. Because it looks awful.

<!DOCTYPE html>
<html lang="en" ng-app>
    <head>
        <meta charset="UTF-8">
        <title>Angular Sample</title>
    </head>
    <body ng-model="isShow" ng-init="isShow=true">

        <p ng-show="isShow"><span ng-cloak>{{ isShow }}</span></p>
        <p ng-show="!isShow"><span ng-cloak>{{ isShow }}</span></p>

        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
    </body>
</html>
Rishabh
  • 3,752
  • 4
  • 47
  • 74
Kotaro
  • 745
  • 2
  • 6
  • 7
  • You didn't specify ng-app a name – mohamedrias Mar 30 '15 at 05:59
  • How is this even parsing the expressions? This is another place where ng-init is incorrectly used; the ng-init directive is not a general purpose initializer, despite it's name. – Claies Mar 31 '15 at 11:15
  • like @AR7 said, you need to put some css to it works. I don't recommend to put angular.js to head section. – Joao Polo Mar 31 '15 at 15:39

12 Answers12

105

Add this css from here

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

and use either the class name or attribute on your parent div or anywhere you have defined your app.

eg:

<div ng-app="Random" class="ng-cloak">
</div>
Yasser Shaikh
  • 46,934
  • 46
  • 204
  • 281
  • 2
    I wish all answers on SO were like this :) – devdropper87 Oct 28 '15 at 23:26
  • Works perfectly but could you please elaborate on these css ? what exactly is it doing ? – Cemre Mengü Nov 21 '15 at 13:47
  • 2
    @Cemre It adds the `display: none` property to all variations of the ng-cloak class and directive. This class will be active during the loading time of your app, so this css makes sure the elements with this class aren't displayed. – Hartger Nov 26 '15 at 09:37
  • 4
    (from @GregL's doc link), a little more about the WHY: The problem with the OP's code is that the code loads the angular.min.js at the end of the page load, so the HTML (Angular template) is rendered before ng-cloak gets defined. Adding the css rule reference here works simply by defining angular's own ng-cloak style in the so it's there (before Angular.min.js is loaded) immediately when the page loads, even if you don't load angular until the end of the HTML. Doc recommends angular.js load in to avoid/minimize this problem. – Mike Jan 04 '16 at 21:13
31

From the Angular docs:

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.

GregL
  • 37,147
  • 8
  • 62
  • 67
11

You have to specify these rules in your CSS:

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  display: none !important;
}
m0meni
  • 16,006
  • 16
  • 82
  • 141
9

Using ngBind should eliminate that as well (I develop in SharePoint sometimes and ngCloak won't work).

AngularJS Docs:

It is preferable to use ngBind instead of {{ expression }} if a template is momentarily displayed by the browser in its raw state before Angular compiles it. Since ngBind is an element attribute, it makes the bindings invisible to the user while the page is loading.

An alternative solution to this problem would be using the ngCloak directive.

JS:

var app = angular.module('test', []);

app.controller('testCtrl', ['$scope', function($scope) {
  $scope.test = "Hello World";
}]);

HTML:

<html ng-app="test">

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
  <script src="script.js"></script>
</head>

<body ng-controller="testCtrl">
  <h1 ng-bind="test"></h1>
</body>

</html>
kenhow
  • 111
  • 2
  • 5
8

Add below in your css file:-

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  display: none !important;
}
squiroid
  • 13,809
  • 6
  • 47
  • 67
  • The OP has not set any name to the `ng-app` directive and using angular 1.3+. Hope thats what preventing it to work – mohamedrias Mar 30 '15 at 06:04
  • @mohamedrias may be possible but he is not using ng-controller or anything related to modules so I guess it will not create a problem in this particular case :) – squiroid Mar 30 '15 at 06:12
6

In my case, I figured that my troubles was dues to pending ajax requests. Ng-cloak probably works for static content, but if a template depends an ajax data then this is thus rendered before receiving the ajax response.

To avoid it I define a directive :

angu

mymodule
        .directive("ajaxCloak", ['$interval', '$http', function ($interval, $http) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    let stop = $interval(() => {
                        if ($http.pendingRequests.length === 0) {
                            $interval.cancel(stop);
                            attrs.$set("ajaxCloak", undefined);
                            element.removeClass("ajax-cloak");
                        }
                    }, 100);

                }
            };
        }]);

With a bit of CSS :

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

Then in your main HTML file:

<div ui-view data-ajax-cloak></div>

Note: this isn't as sophisticated as ng-cloak as this is a global cloack, it hides everything until all requests are finished.

Rolintocour
  • 2,934
  • 4
  • 32
  • 63
5

My solution I think i tried all of above suggestions but nothing worked. Some uses ng-include but it seems a little bit to much, further it could be scary with the inner scope that gets created. So it tried it by using style and ng-style. In my affected main div.

<div class="container" style="display:hidden;" ng-style="loaded">

Then I set the scope variable loaded in my base controller.

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

Still got all those {{ }}. Weird when display sets to block only when angularjs has loaded. Then I noticed that I had the firefox f12 developer console running. Its doing stuff. Stupid me

Jens Alenius
  • 1,931
  • 2
  • 16
  • 20
3

From angular 1.3 onwards, you must specify a name for ng-app attribute for it to work.

<html lang="en" ng-app="myApp">

IN your JS:

angular.module("myApp",[])

This will make the angular to bootstrap.

But for the current situation, as you are loading angular at the bottom of the page, it's taking time to load. So the css required for the ng-cloak is not available yet.

Either move the js to the tag or load the specific CSS code to your CSS to make it work.

[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  display: none !important;
}
mohamedrias
  • 18,326
  • 2
  • 38
  • 47
2

I have tried all of the answers above and a lot beyond, with no help. My (large) page would flicker on each load. My solution was to add this just after body tag:

<div style="display:flex" opacity=0>
  <status-progress></status-progress>
  <h3>Loading... </h3>
</div>

and to wrap everything in the page:

<div class="loaded" style="opacity: 0" opacity=1> ... </div>

directive:

app.directive('opacity', opacity);
    function opacity($timeout) {
        return {
            link: function (scope, element, attrs) {
                var value = attrs.opacity;
                $timeout(function () {
                    element[0].style.opacity = value;
                },500);
            }
        }
    }

To make the page appear "smoother", the stylesheet:

.loaded{
    transition: opacity 1s ease-in-out;
    -webkit-transition: opacity 1s ease-in-out;
    -moz-transition: opacity 1s ease-in-out;
}

This way, you see "Loading" for 1sec, while everything is getting ready.

Vega
  • 27,856
  • 27
  • 95
  • 103
1

Since none of these answers gave me the desired result, I accomplished what I wanted by creating a directive very similar to ng-cloak but wrapping the code in a $timeout so that it will wait until the end of the $digest cycle to remove the cloaking attribute and/or class. This was the only way I was able to truly hide the {{}} bindings in the browser.

angular.directive('myCloak', function($timeout) {
  return {
    restrict: 'A',
    compile: function (element, attr) {
      $timeout(function () {
        attr.$set('myCloak', undefined);
        element.removeClass('my-cloak');
      });
    }
  };
});

And don't forget, you will have to add a custom css rule for this new attribute / class:

[my\:cloak], [my-cloak], [data-my-cloak], [x-my-cloak], .my-cloak, .x-my-cloak {
  display: none !important;
}
jtate
  • 2,612
  • 7
  • 25
  • 35
0

Using the fix recommended here works for me...

https://github.com/opitzconsulting/jquery-mobile-angular-adapter/issues/167

CSS:

.my-cloak {
  display: none  !important;
}

JS:

$scope.$on('$viewContentLoaded', function(){
    $('.my-cloak').removeClass('my-cloak');
});

HTML:

div(class="my-cloak")
Samir Seetal
  • 392
  • 6
  • 8
0

Use ngBind when ng-cloak is not available.

<p ng-show="!isShow" ng-bind="isShow"></p>
Tushar
  • 3
  • 4