Угловая реализация генетического резольвера - PullRequest
1 голос
/ 25 октября 2019

Уже некоторое время пытаюсь внедрить генетический распознаватель в мое приложение. Моя первая реализация, основанная на моей интуиции, дала мне точный результат в виде этого SO вопроса: Как предоставить сервис, который использует дженерики в Angular4? , что, конечно, также дало мне точную ошибку.

Я пытался решить его, используя исключенный ответ (используя InjectionToken), но не смог заставить его работать, возможно, я недостаточно опытен в использовании InjectionToken, мой текущий код:

GenericResolverService

`export interface GetItem<T> {
  getItem(id: number): Observable<T>;
 }

@Injectable()
export class GenericResolverService<T, U extends GetItem<T>> 
  implements Resolve<T> {

constructor(private dataService: U,
            private router: Router) {

}

resolve(route: ActivatedRouteSnapshot, 
      stata: RouterStateSnapshot):
  Observable<T> | Observable<never> {
  const itemId = +route.paramMap.get('id');

  return this.dataService.getItem(itemId).pipe(
    take(1),
    mergeMap(item => {
        if (item) {
            return of(item);
        } else {
            this.router.navigate(['/error/not-found']);
            return EMPTY;
        }
    })
  );
}
}`

Модуль маршрутизатора

const ITEM_RESOLVER = 
    new InjectionToken<GenericResolverService<ItemMasterData,   ItemMasterDataService>>
    ('itemResolver');

const routes: Routes = [
{ 
    path: ':id', component: ItemMasterDataEditComponent,
    resolve: {
        item: ITEM_RESOLVER
    } 
}
];

 @NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: [{ provide: ITEM_RESOLVER, useClass: GenericResolverService}]
})
export class ItemMasterDataRoutingModule { }   

ItemMasterDataService

@Injectable()
export class ItemMasterDataService implements GetItem<ItemMasterData> {

  public getItem(id: number): Observable<ItemMasterData> {

  ...
}

Текущий код выдает ошибку:

Ошибка: не удается разрешить все параметры для GenericResolverService: (?, [Объект Object]).

Что я делаю неправильно?

1 Ответ

1 голос
/ 25 октября 2019

Angular требует, чтобы токен DI был доступен во время выполнения, но вы используете универсальный тип, который исчезнет из сгенерированного JavaScript.

Если вы внимательно прочитаете ответ на вопрос, который вы связали, вы можете заметить, что базовый универсальныйкласс не был предоставлен вообще, а скорее производный класс:

providers: [{ provide: MESSAGE_RESOLVER, useClass: MessageResolver }]
                                                   ^^^^^^^^^^^^^^^^^

, который содержит определенный токен в своем конструкторе:

export abstract class DetailResolver<T, R extends Repository<T>> implements Resolve<T> {
   constructor(protected repositoryService: R, protected router: Router) {}
}

@Injectable()
export class MessageResolver extends DetailResolver<Message, MessageService> {
   constructor(repositoryService: MessageService, router: Router) {
                                  ^^^^^^^^^^^^^^
                                  available at runtim
     super(repositoryService, router);
   }
}

В вашем примере вы все еще пытаетесь передать класс с помощьюуниверсальные параметры конструктора, но Angular не знает, какой класс создавать.

Таким образом, вы можете либо создать производный класс, как в примере выше, либо использовать альтернативный рецепт для DI (useFactory):

{
  provide: ITEM_RESOLVER,
  useFactory: (service, router) => new GenericResolverService(service, router),
  deps: [ItemMasterDataService, Router]
}

Кроме того, вы можете использовать свой универсальный класс в качестве токена:

const routes: Routes = [
  { 
    path: ':id', component: ItemMasterDataEditComponent,
    resolve: {
        item: GenericResolverService
    } 
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
  providers: [
     ItemMasterDataService,
     {
       provide: GenericResolverService,
       useFactory: (service, router) => new GenericResolverService(service, router),
       deps: [ItemMasterDataService, Router]
     }
  ]
})
export class ItemMasterDataRoutingModule { }  

Еще один вариант - использовать реальный токен для вашего dataService

constructor(protected dataService: SomeBaseDateServiceClass) {}

и предоставлять различные реализации на разныхуровни вашего приложения:

{ provide: SomeBaseDateServiceClass, useClass: ItemMasterDataService }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...