Распределитель угловых маршрутов не разрешается - PullRequest
0 голосов
/ 23 мая 2019

У меня возникла ситуация с Angular, когда распознаватель данных маршрутизации выглядит так, как будто он готов правильно вернуть данные, но тогда разрешение никогда не происходит.Это особенно странно, потому что у меня есть параллельное расположение для другого компонента, и он там работает нормально.

Приложение извлекает данные о массиве событий через HTTP.В EventListComponent все события возвращаются распознавателем в ответ на /events, и компонент правильно отображает их.В компоненте EventDetails в моем текущем порядке я по-прежнему извлекаю все события через HTTP, а затем в обработчике в ответ на /events/[the event ID] выбираю событие, в котором должны отображаться его данные.(Это из курса Pluralsight Angular Fundamentals, если он звучит знакомо. Но я склонен смотреть видео, а затем прорабатывать их в своем собственном порядке, чтобы попытаться закрепить навыки в своей голове.)

remote-event.service.ts

import { Injectable, EventEmitter } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { IEvent } from './event.model';

@Injectable()
export class RemoteEventService {

  constructor(
    private http: HttpClient
  ) {}

  getEvents(): Observable<IEvent[]> {
    return this.http.get<IEvent[]>('/api/ngfdata/events.json');
  }

  getEventById(id: number): Observable<IEvent> {
    console.log(`In getEventById: id = ${id}`);
    const emitter = new EventEmitter<IEvent>();
    this.getEvents().subscribe(
      (events) => {
        emitter.emit(events.find((event) => event.id === id));
      }
    );
    return emitter;
  }

export interface ISessionSearchResult {
  eventId: number;
  sessionId: number;
  sessionName: string;
}

Если я не использую распознаватель, компонент EventDetails работает нормально.Это работает:

eventRoutes (это дочерний маршрут, ответвляющийся от / events /)

import { Routes } from '@angular/router';
import { EventListComponent, EventDetailsComponent,
  CreateEventComponent, UnsavedNewEventGuard,
  EventListResolver, EventDetailResolver
} from './index';

export const eventRoutes: Routes = [
  { path: 'create', component: CreateEventComponent,
    canDeactivate: [UnsavedNewEventGuard]
  },
  { path: ':id', component: EventDetailsComponent/*,
    resolve: { event: EventDetailResolver }*/
  },
  { path: '', component: EventListComponent,
    resolve: { events: EventListResolver }
  }
];

event-details.component.ts

import { Component, Input, OnInit, inject, Inject } from '@angular/core';
import { RemoteEventService } from '../shared/remote-event.service';
import { ActivatedRoute, Params } from '@angular/router';
import { IEvent } from '../shared/event.model';
import { TOASTR_TOKEN } from 'src/app/common/3rd-party/toastr.service';

@Component(
  {
    selector: 'event-detail',
    templateUrl: './event-details.component.html',
    styles: [`
      .container { padding-left: 20px; padding-right: 20px; }
      .event-image { height: 100px; }
      .btn-group:first-child {
        margin-right: 24px;
      }
      .btn-group {
        border: medium solid green;
      }
      .btn-group .btn:not(:first-child) {
        border-left: thin solid green;
      }
    `]
  }
)
export class EventDetailsComponent implements OnInit {
  event: IEvent;
  filterBy = 'all';
  sortBy = 'name';

  constructor(
    private eventService: RemoteEventService,
    private route: ActivatedRoute,
    @Inject(TOASTR_TOKEN) private toast
    ) {
      console.log('In EventDetailsComponent.constructor');
    }

/*   ngOnInit() {
    console.log('At start of EventDetailsComponent.ngOnInit');
    this.event = this.route.snapshot.data['event'];
    console.log('At end of EventDetailsComponent.ngOnInit');
  }
*/

  ngOnInit() {
    console.log('At start of EventDetailsComponent.ngOnInit');
    this.route.params.forEach((params: Params) => {
      this.eventService.getEventById(+params.id).subscribe(
        (event) => this.event = event
      );
    });
    console.log('At end of EventDetailsComponent.ngOnInit');
  }

  flashSessionSummary(message: string) {
    this.toast.info(message);
  }
}

enter image description here

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

У меня включена трассировка маршрута.Без использования резольвера:

enter image description here

При активном резольвере:

enter image description here

Вот преобразователь:

event-detail-resolver.service.ts

 import { Injectable, Input } from '@angular/core';
import { RemoteEventService } from '../shared/remote-event.service';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { IEvent } from '../shared/event.model';

@Injectable()
export class EventDetailResolver implements Resolve<IEvent> {

  constructor(
    private eventService: RemoteEventService
  ) {}

  resolve(route: ActivatedRouteSnapshot) {
    console.log(`In resolve(): id = ${route.params.id}`);
    const e = this.eventService.getEventById(+route.params.id);
    console.log(`The observable that resolve() is about to return: ${JSON.stringify(e)}`);
    e.subscribe((evt) => console.log(`The value that the observable resolves to: ${JSON.stringify(evt)}`));
    return e;
  }

}

Как вы можете видеть, перед возвратом Observable я подписываюсь на негопоэтому я могу продемонстрировать здесь в резольвере значение, к которому он будет разрешаться - и это правильное значение объекта события.Если бы вы не сказали, что подписка на него здесь препятствует разрешению решателя, ну, нет, я добавил, что в целях отладки после он уже не работал.Когда я комментирую его обратно, я получаю точно такой же результат (за исключением того, что этот вызов console.log не выполняется): распознаватель никогда не разрешается.

Что странно, поскольку моя явная подписка на Observable демонстрируетчто он должен давать правильное значение.

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

Есть мысли?

1 Ответ

2 голосов
/ 23 мая 2019

Попробуйте использовать оператор

take(1) или first

, чтобы отметить завершение Observable.Решение ожидает завершения Обсервейла, прежде чем продолжить.Если Obserable не завершит работу, resovler не вернется.

Ваш код будет выглядеть примерно так:

import { Injectable, Input } from '@angular/core';
import { RemoteEventService } from '../shared/remote-event.service';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { take } from 'rxjs/operators';
import { IEvent } from '../shared/event.model';

@Injectable()
export class EventDetailResolver implements Resolve<IEvent> {

  constructor(
    private eventService: RemoteEventService
  ) {}

  resolve(route: ActivatedRouteSnapshot) {
    console.log(`In resolve(): id = ${route.params.id}`);
    const e = this.eventService.getEventById(+route.params.id);
    console.log(`The observable that resolve() is about to return: ${JSON.stringify(e)}`);
    e.subscribe((evt) => console.log(`The value that the observable resolves to: ${JSON.stringify(evt)}`));
    return e.pipe(take(1));
  }

}

Посмотрите на этот github обсуждение вэто поведение.

...