Получение необходимых данных перед инициализацией приложения в Angular 6 - PullRequest
0 голосов
/ 27 января 2019

Я создал службу, которая получает некоторые данные с сервера, и они необходимы для создания моих компонентов и должны вызываться один раз, потому что это вызывает огромную нагрузку на сервер.когда я использую сервис в поставщике модуля приложения, он ждет получения необходимых данных и получает его успешно, потому что я могу зарегистрировать его, но после этого, когда я хочу получить его в компоненте, он возвращает Undefined!

попытался уменьшить инициализации службы до 1, удалив UserService из провайдеров, но это вызывает ошибки.

Функция, которая получает информацию:

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;
}

Фабрика, которая будет использоваться в APP_INITIALIZATION:

export function adminProviderFactory(provider: UserService) {
  return () => provider.getAdminInitInfo();
}

Провайдеры AppModule:

providers: [
    AuthGuardService,
    AuthService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptorService,
      multi: true
    },
    UserService,
    {
      provide: APP_INITIALIZER,
      useFactory: adminProviderFactory,
      deps: [UserService],
      multi: true
    }
]

Журнал данных, которые я получаю в компоненте:

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

После этой процедуры 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;
}

В таких компонентах, как:

ngOnInit() {
    this.params = this.userService.getSomethingData();
}

Ответы [ 2 ]

0 голосов
/ 27 января 2019

То, что вы спрашиваете, это способ выполнения требований к компонентам. Это можно сделать с помощью распознавателя в вашей маршрутизации.

Основные ингредиенты:

Служба , которая содержит информацию, которую вы запрашиваете (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;
    }
}

Средство распознавания , представляющее собой фрагмент кода, который запускается перед выполнением вашего маршрута и разрешает все, что вам нужно. Преобразователь завершен, когда завершен наблюдатель.

@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();
    }
}

Маршрутизация , то есть просто защитите свою маршрутизацию с помощью распознавателя:

    path: '',
    component: MyLayout,
    canActivate: [AuthGuard],
    children: [
        { path: 'home', component: HomeComponent },
        { path: 'page1', component: Page1Component },
        { path: 'page', component: APage2Component },
    ],
    resolve: { data: AuthenticatedAppResolver },

Ваши компоненты и сервис должны быть зарегистрированы в разделе providers вашего модуля. Затем вы можете свободно использовать getCachedData() метод ApplicationService в любых компонентах, защищенных распознавателем.

Обратите внимание, что распознаватель может вызываться более одного раза, но, поскольку мы кэшируем сервис, мы не будем спрашивать их каждый раз.

Обновление

Этот метод работает, пока у вас не будет 1 уровня субмодулей. Если это усложняется или вы хотите, чтобы более чем один модуль использовал эти данные, лучше создать родительский модуль и разрешить весь маршрут, а затем записать маршруты в модуль маршрутизации. Пример: * +1032 *

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
    }
  },
]
0 голосов
/ 27 января 2019

Полагаю, ваш подход слишком сложен.И вы никогда не вернете значение response.Попробуйте вместо этого:

getAdminInitInfo(): Promise<any> {
    return this.http.get<AdminInit>(baseUrl + '/panel/admin/initial/')
    .toPromise()
    .then(
         response => { return response.json(); }
    );
}

response.json() уже возвращает обещание.

Или даже короче:

getAdminInitInfo(): Promise<any> {
    return this.http.get<AdminInit>(baseUrl + '/panel/admin/initial/')
    .toPromise()
    .then(
         response => response.json()
    );
}
...