user1834464
user1834464

Reputation:

Directive rendering delay when using angularjs and requirejs

Basically, my problem is that "I am {{ 10 + 13 }}" is what is being rendered for a second/half a second, before the "store" module is being created in main.js.

<!DOCTYPE html>
<html lang="en" ng-app="store">
    <head>
        <title>...</title>
        <script data-main="main.js" src="../bower_components/requirejs/require.js"></script>
        <link href="../bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    I am {{ 10 + 13 }}
</body>

main.js sets the requirejs configs, requires the angular library and sets the "store" module:

require.config({
    paths: {angular: '../bower_components/angular/angular.min'},
    shim: {angular: {exports: 'angular'}}
});

require(['angular'], function(angular) {
    var app = angular.module('store', []);
});

I think the reason this occurs, is because main.js and the angular library are being loaded asynchronously by requirejs (with an "async" attribute on the script tag), so the DOM gets rendered before the store module has been created, thus creating a delay.

What would I have to do to avoid this gap that occurs between rendering "I am {{ 10 + 13 }}" and "I am 13"? I could load both main.js and the angular js synchronous/without requirejs, but that does not seem like a best practice.

Upvotes: 2

Views: 1520

Answers (3)

Kalhan.Toress
Kalhan.Toress

Reputation: 21901

I think you can use ng-cloack directive

<body>
    I am <span ng-cloak>{{ 10 + 13 }}</span>
</body>

add css

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

didn't test you can give a try. :)

Example

UPDATE

hide the <body> until angular available.

.initial-hide {
   display: none;
}

.show {
    display: block !important;
}


<body class="initial-hide" ng-class="{show : initedScripts}">
    ......
    ......
</body>

body will get initial-hide and gets hide until show class applied to it. show class applied when variable initedScripts sets to true.

in the JS

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

app.run(function($rootScope) {
     $rootScope.initedScripts = true;
});

set `initedScripts` to `true` in the run block and that means angular loaded successfully.

here is a DEMO

i added a 2 seconds timeout to delay the invoking of angularjs by requirJs

Upvotes: 2

user1834464
user1834464

Reputation:

As @K.Toress mentioned, the way to fix this problem would be to use ng-cloak on the body element or more specifically on the problematic elements to improve the rendering of the page.

Some css/style is needed to put the ng-cloak elements in display: none;, so if you are using angular in CSP mode, you will have no problem, because the angular-csp.css stylesheet would normally be included. However, if you are not using angular in CSP mode, the css rule embedded within angular.js/angular.min.js would not have any effect, since the library will most likely be loaded after the DOM is completely loaded. For this reason, you need to manually add some style for the [ng-cloak]elements:

<head>
    ...
    <style>[ng-cloak] {display: none;}</style>
</head>

For your information, since angular can be loaded after the DOM or before the code base, you should not include an ng-app attribute to the document, but rather bootstrap angular manually to avoid any asynchronous issues:

require(['angular'], function(angular) {
    var app = angular.module('app', []);
    angular.bootstrap(document, ['app']);
});

Upvotes: 0

Kirill Slatin
Kirill Slatin

Reputation: 6143

You can wrap your expressions to be interpolated in some custom tags that are supported by angular. Thus they won't be rendered by browser before angular is loaded and compiles all stuff on your page.

Which one to choose depends on your real markup. You can even wrap this in a custom directive

Upvotes: 0

Related Questions