Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to preload angular2 views so will not flicker white page on first load?

I am building an angular 2 app in plain JS. My problem is that when I change from a page to another it flicker a white page until the new view is rendered. This happens for all components only first time I access them. If I go to same route second time the page is loaded without white page. I capture the screen to explain better my problem: https://drive.google.com/file/d/0B5pOsXT-4rdTbmtuVnlUdXRMdE0/view?usp=sharing

Here is my main view:

<router-outlet></router-outlet>

<nav id="menu">
    <a [routerLink]="['Page1']">Page 1</a>
    <a [routerLink]="['Page2']">Page 2</a>
    <a [routerLink]="['Page3']">Page 3</a>
    <a [routerLink]="['Page4']">Page 4</a>
    <a [routerLink]="['Page5']">Page 5</a>
</nav>

RouteConfig is defined like this:

AppComponent = ng.router
    .RouteConfig([
        {path: '/page1', name:"Page1", component: Page1Component, useAsDefault: true },
        {path: '/page2', name:"Page2", component: Page2Component},
        ...
    ])
    (AppComponent);

And all my components have a .html file and a .css file like this:

Page1Component = ng.core
    .Component({
        selector: 'rl-page1',
        templateUrl: 'app/components/page1/view.html',
        styleUrls: ['app/components/page1/style.css'],
        directives: [ng.router.ROUTER_DIRECTIVES]
    })
    .Class({
        constructor: [ng.router.Router, function(router) {
            this.router = router;


        }]
    });

From what it looks like angular cache pages after I access them and at second access will display instantly (without white flickering). I search how I can preloade this but I can't find any answer or method on this.

Please let me know if you need more code.

(I don't use Page1, Page2 in real app, only for this question I changed to be more clear for example)

Thanks.

EDIT: 2016-03-18

I try to use DynamicComponentLoader to load all the components in a hidden div. The code looks like this in AppComponent:

ngOnInit: function(){
    this.dcl.loadIntoLocation(Page1Component, this.elementRef, 'preloadpages');
    this.dcl.loadIntoLocation(Page2Component, this.elementRef, 'preloadpages');
},

and the html where is loaded is: <div style="display: none;"><div #preloadpages></div></div>

But I faced 2 problems:

  1. If one of my component has in the constructor RouteParams like this:

    constructor: [ng.router.RouteParams, function(routeParam) { ... }], I am getting this error: EXCEPTION: No provider for RouteParams! (class19 -> RouteParams)

  2. All components are loaded just like you open it. If I have a ajax call in a constructor that ajax call is created and all the components html will be appended in my hidden div. Here can be a performance problem if at start I try to load like 5 components and some make ajax calls. I am looking if there is a solution to load only html + css or to send a flag to component constructor to know that I am loading hidden just for preaching.

Thanks.

like image 616
Daniel Dudas Avatar asked Feb 26 '16 12:02

Daniel Dudas


2 Answers

Paraphrasing https://stackoverflow.com/a/37298914/441662

The problem is that the files are loaded separately, which you can prevent using something like webpack that compiles the sources into bundles which can include both your app and the templates used in the routes. (altough I still can't explain the jump to the top of the page).

Here's how you can modify the webpack config of the angular/angular2-seed project:

package.json

"devDependencies": {
  ...,
  "html-loader": "^0.4.3",
},

webpack.config.js

module: {
  loaders: [
    ...,
    { test: /\.html$/, loader: 'html' }
  ]
}

Example usage in your-component.ts

@Component({
  template: require('app/components/your-component/your-component.html')
})

Now the routes are loaded instantly and there is no flickering or jumping going on.

like image 127
Benny Bottema Avatar answered Nov 07 '22 05:11

Benny Bottema


Add a wrapper around the <router-outlet>

<div [hidden]="!isInitialized">
  <router-outlet></router-outlet>
</div>

In the page component set isInitialized to false. Then call

this.router.navigate(['Page1'])
.then(_ => this.router.navigate(['page2']))
.then(_ => this.router.navigate(['page3']))
...
.then(_ => {
    this.isInitialized = true; 
    this.router.navigate(['Page1']);
});
like image 42
Günter Zöchbauer Avatar answered Nov 07 '22 04:11

Günter Zöchbauer