最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular 2 delay rendering of router-outlet - Stack Overflow

programmeradmin5浏览0评论

I'm developing an Angular 2 app with multiple ponents that rely on some data that is loaded from the server via the http-service (it's data about the user and his roles).

Most of my route ponents throw errors within their ngOnInit() methods if this data is not already loaded. The data is loaded and stored within a service that is injected in all ponents.

Is there a way to delay the rendering of the current route within my root-ponent until the http call is finished?

Otherwise I would have to implement some kind of check and retry mechanism within the ngOnInit of all the route ponents, which would be very awkward.

I already tried to hide the router-outlet element until the call finished but this leads to an error saying "Cannot find primary outlet to load xxx"

I'm developing an Angular 2 app with multiple ponents that rely on some data that is loaded from the server via the http-service (it's data about the user and his roles).

Most of my route ponents throw errors within their ngOnInit() methods if this data is not already loaded. The data is loaded and stored within a service that is injected in all ponents.

Is there a way to delay the rendering of the current route within my root-ponent until the http call is finished?

Otherwise I would have to implement some kind of check and retry mechanism within the ngOnInit of all the route ponents, which would be very awkward.

I already tried to hide the router-outlet element until the call finished but this leads to an error saying "Cannot find primary outlet to load xxx"

Share Improve this question asked Dec 8, 2016 at 10:13 SimonSimon 2964 silver badges17 bronze badges 2
  • The service is the same everwhere? If yes, you could use APP_INITIALIZER to handle this problem – LoïcR Commented Dec 8, 2016 at 10:18
  • 1 You can use Resolve class and create a Resolver as a data provider for your ponents, it gathers data before your ponent is initialized. – ulubeyn Commented Dec 8, 2016 at 11:07
Add a ment  | 

2 Answers 2

Reset to default 6

There is an option to delay of router initial navigation when creating Router module:

RouterModule.forRoot([
    // routes here
], {
    initialNavigation: false // the propery to delay navigation
}),

Later the initial navigation can be triggered via Angular Router, like this:

this.router.initialNavigation();

I acplished this with a CanActivate guard. The key to making it work is returning an Observable from the canActivate method. That way, you can delay as long as you need to.

import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { StateService } from '../../_services/state.service';
import { Subject } from 'rxjs/Rx';
import { Subscription } from 'rxjs/Subscription';

@Injectable()
export class LoadingGuard implements CanActivate {
    constructor(private state: StateService) {}

    public canActivate(): Observable<boolean> {
        if (!this.state.loading$.getValue()) { 
            return Observable.of(true); 
        }

        let subject = new Subject<boolean>();
        let subscription = this.state.loading$.subscribe(value => {
            if (!value) {
                subject.next(true);
                subject.plete();

                subscription.unsubscribe();
            }
        });

        return subject;
    }
}

Above, StateService is a service that evaluates the current user and pre-caches some data for the rest of the app. It has a subject named loading$ that returns false when loading has pleted.

All that's left is to declare the guard in the app module.

import { LoadingGuard } from './app/loading-guard/loading-guard';
// other imports omitted

@NgModule({
    // other module properties omitted
    providers: [LoadingGuard]
})
export class AppModule {}

Then declare the guard in your routing.

import { LoadingGuard } from './app/loading-guard/loading-guard';
// other imports omitted

export const rootRouterConfig: Routes = [
    { path: 'app', ponent: AppComponent, 
      canActivate: [LoadingGuard], 
      children: [
        { path: 'index', ponent: IndexComponent },
        // child routes omitted
      ] },
    { path: 'sign-in', ponent: SignInComponent },
    { path: '**', redirectTo: 'sign-in' }
];

For reference, here's the documentation on CanActivate: https://angular.io/docs/ts/latest/api/router/index/CanActivate-interface.html

发布评论

评论列表(0)

  1. 暂无评论