Как дождаться завершения работы преобразователя базового класса до выполнения преобразователя производного класса?

#angular #typescript

#angular #typescript

Вопрос:

Многим моим преобразователям (@angular / router Resolve) необходимо запрашивать одни и те же данные перед выполнением запроса, зависящего от маршрута. Я хотел бы использовать базовый класс преобразователя, который разрешает исходные данные перед выполнением resolve() в производном классе.

Базовый класс:

 export class MyBaseResolver implements Resolve<Observable<string>> {
      
        myBaseProperty: string;

        constructor(service: MyService) {}
        
        resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): string {
    
            this.service.getData()
                .subscribe((data) => {
                    this.myBaseProperty = data;
            });
        
        }
}
  

Производный класс:

 export class MyDerivedResolver implements Resolve<Observable<Thing>> extends MyResolverParent {

        constructor(public service: MyService) {
            super(service);
        }
        
        // How to make this wait for MyBaseResolver.resolve() to complete 
        // so "myBaseProperty" is available?
        resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Thing> {
    
            return this.service.getOtherData(myBaseProperty);
        
        }
}
  

Как я могу MyDerivedResolver дождаться MyBaseResolver.resolve() завершения, чтобы so myBaseProperty был доступен и действителен?

Комментарии:

1. Я не знаком с преобразователем, но вы не можете возвращать синхронные данные ( data здесь ) из асинхронного вызова ( this.service.getData() здесь ).

2. @MichaelD да, вы правы, это ошибка в примере, который я создал, и я не заметил ее перед публикацией. Спасибо, что указали на это.

Ответ №1:

 export class MyDerivedResolver implements Resolve<Observable<Thing>> extends MyResolverParent {

        constructor(public service: MyService) {
            super(service);
        }
        
        // How to make this wait for MyBaseResolver.resolve() to complete 
        // so "myBaseProperty" is available?
        resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Thing> {
            
            return super.resolve(route, state).pipe(mergeMap(()=>this.service.getOtherData(myBaseProperty)));
        
        }
}
  

но, честно говоря, я не понимаю, почему вы хотите разрешить this.service.getData() из базового класса.

Комментарии:

1. Хорошее предложение, я попробую. Причина, по которой я хотел бы это сделать, заключается в том, что все мои классы преобразователей требуют одинаковой информации (идентификаторов), прежде чем смогут запрашивать свои собственные данные. Вместо того, чтобы повторять один и тот же запрос в каждом классе преобразователя, я бы хотел инкапсулировать этот код в базовый класс, чтобы преобразователям нужно было только наследовать от него. Надеюсь, это все объясняет. Основываясь на предложенных решениях, базовому классу даже не нужно реализовывать Resolve интерфейс, что на самом деле делает его еще проще.

2. Точно. Это также необходимо изменить const data = await this.service.getData().toPromise(); const data = this.service.getData(); в вашем базовом классе

Ответ №2:

Не тестировал, но я бы выбрал именно этот подход

 export class MyBaseResolver implements Resolve<Observable<string>> {
      
        myBaseProperty: string;

        constructor(service: MyService) {}
        
        async resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): string {
    
            const data = await this.service.getData().toPromise();
            this.myBaseProperty = data;
            return data;
        
        }
}
  

Комментарии:

1. Хорошее предложение, я попробую. Я не знаю, позволит ли Typescript Resolve реализовать метод интерфейса resolve() как асинхронный, но это достаточно просто попробовать.