在 Angular 6 中的应用程序初始化之前获取所需的数据

W1l*_*orm 3 observable rxjs typescript angular angular6

我创建了一个从服务器获取一些数据的服务,它们是制作我的组件所必需的,并且应该被调用一次,因为它会导致服务器上的巨大负载。当我在应用程序模块提供程序中使用服务时,它会一直等到获取所需的数据,并且它确实成功获取了它,因为我可以记录它,但是之后当我想在组件中获取它时,它返回未定义!

我试图通过从提供者中删除 UserService 来将服务的初始化减少到 1,但这会导致错误。

获取信息的函数:

getAdminInitInfo(): Promise<any> {
var vm = this;
const promise = this.http.get<AdminInit>(baseUrl + '/panel/admin/initial/')
  .toPromise()
  .then(
    response => {
      vm.adminInitInfo = response;
      console.log(response);
    }
  )
return promise;
}
Run Code Online (Sandbox Code Playgroud)

将在 APP_INITIALIZATION 中使用的工厂:

export function adminProviderFactory(provider: UserService) {
  return () => provider.getAdminInitInfo();
}
Run Code Online (Sandbox Code Playgroud)

AppModule 提供者:

providers: [
    AuthGuardService,
    AuthService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptorService,
      multi: true
    },
    UserService,
    {
      provide: APP_INITIALIZER,
      useFactory: adminProviderFactory,
      deps: [UserService],
      multi: true
    }
]
Run Code Online (Sandbox Code Playgroud)

我在组件中获得的数据日志:

user.service.ts:23 service started 
user.service.ts:23 service started 
user.service.ts:70 {filters: {…}}
user.service.ts:78 undefined
overview.component.ts:19 undefined
Run Code Online (Sandbox Code Playgroud)

在这个过程之后,adminInitInfo 应该在我需要它的时候使用这个函数返回:

getSomethingData() {
    var data = {};
    console.log(this.adminInitInfo);
    if (!this.adminInitInfo) {
      return undefined;
    }
    data['something'] = this.adminInitInfo.filters.something;
    data['something2'] = this.adminInitInfo.filters.something2;
    data['something3'] = this.adminInitInfo.filters.something3;
    return data;
}
Run Code Online (Sandbox Code Playgroud)

在一个组件中,例如:

ngOnInit() {
    this.params = this.userService.getSomethingData();
}
Run Code Online (Sandbox Code Playgroud)

Pie*_*ier 5

您要问的是一种满足组件要求的方法。这可以通过在路由中使用解析器来完成。

主要成分如下:

ApplicationData包含您需要的信息的服务(是我的一类,包含有关应用程序的信息,例如用户名、版本等...,在此上下文中无关紧要):

@Injectable()
export class ApplicationService {
    private cachedData: ApplicationData = null;

    public constructor(/* place here your dependencies */) {
    }

    public initializeApplicationData(): Observable<ApplicationData> {
        // return here the observable that builds your application data, like for example getting the user, and joining it with the version and tap it:

        // if we already have the data, don't ask anything and simply return it
        if (this.cachedData)
            return of(this.cachedData);

        return /* your service that builds the application data */.getApplicationData().pipe(
            tap(x=> this.cachedData = x));
    }

    public getCachedData(): ApplicationData {
       return this.cachedData;
    }
}
Run Code Online (Sandbox Code Playgroud)

解析器是在路由发生之前运行的代码段,它可以解析您需要的所有内容。当观察者完成时,解析器完成。

@Injectable()
export class AuthenticatedAppResolver implements Resolve<Observable<ApplicationData>> {

    public constructor(private applicationService: ApplicationService) { }

    public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<ApplicationData> {
        return this.applicationService.initializeApplicationData();
    }
}
Run Code Online (Sandbox Code Playgroud)

路由,即简单地使用解析器保护您的路由:

    path: '',
    component: MyLayout,
    canActivate: [AuthGuard],
    children: [
        { path: 'home', component: HomeComponent },
        { path: 'page1', component: Page1Component },
        { path: 'page', component: APage2Component },
    ],
    resolve: { data: AuthenticatedAppResolver },
Run Code Online (Sandbox Code Playgroud)

您的组件和服务必须在providers您的模块部分注册。然后你就可以在任何受解析器保护的组件中自由使用 的getCachedData()方法ApplicationService

请注意,解析器可能会被多次调用,但是,当我们缓存在服务中时,我们不会每次都询问它们。

更新

此方法一直有效,直到您拥有 1 个级别的子模块。如果它变得更复杂,或者您想要多个模块来使用这些数据,最好创建一个父模块并解析整个路由,然后在该路由模块中编写路由。例子:

const routes: Routes = [
  {
    path: 'login',
    component: LoginComponent
  },
  {
    path: '',
    component: MyLayout,
    canActivate: [AuthGuard],
    children: [
      {
        path: 'dashboard',
        children: [
          {
            path: '',
            component: DashboardComponent
          },
        ]
      },
      {
        path: 'publisher',
        loadChildren: './modules/publisher/publisher.module#PublisherModule'
      }
    ],
    resolve: {
      data: AuthenticatedAppResolver
    }
  },
]
Run Code Online (Sandbox Code Playgroud)