Маршрутизатор Angular 2, использующий BehaviorSubject, наблюдаемый в Resolve

Я пытаюсь настроить конфигурацию своего маршрутизатора с помощью Resolve, который возвращает Observable из BehaviorSubject. Я пробовал это как в angular 4.0.0-beta8, так и в angular 2.4.8 + router 3.4.8

Вот моя услуга:

@Injectable()
export class MyService {
    private _data: BehaviorSubject<Array<string>> = new BehaviorSubject(undefined);

    constructor() {}

    public getData(): Observable<Array<string>> {

        this._data.next(['test1', 'test2', 'test3']);

        let asObservable = this._data.asObservable().delay(1000);
        asObservable.subscribe((myData) => {
            console.log([myData, 'this console message DOES show up']);
        });

        // if I return here, my component's constructor and ngOnInit never fire
        // return asObservable;

        let fakeObservable = Observable.of(['test1', 'test2', 'test3']).delay(1000);
        fakeObservable.subscribe((fakeData) => {
            console.log([fakeData, 'this console message shows up']);
        });

        console.log([asObservable, fakeObservable]);
            /* console log output
            Observable {
                _isScalar: false,
                operator: DelayOperator,
                source: Observable {
                    _isScalar: false,
                    source: BehaviorSubject {
                        _isScalar: false,
                        _value: ['test1', 'test2', 'test3'],
                        closed: false,
                        hasError: false,
                        isStopped: false,
                        observers: Array[1],
                        thrownError: null,
                        value: ['test1', 'test2', 'test3']
                    }
                }
            },
            Observable {
                _isScalar: false,
                operator: DelayOperator,
                source: ScalarObservable {
                    _isScalar: true,
                    scheduler: null,
                    value: ['test1', 'test2', 'test3']
                }
            }
            */

        return fakeObservable; // this WILL reach my component constructor and ngOnInit
    }
}

Вот моя решимость

@Injectable()
export class MyResolver implements Resolve<Array<string>> {

    constructor(private myService: MyService) {}

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Array<string>>|undefined {
        return this.myService.getData();
    }
}

Вот роутер

RouterModule.forChild([{
    path: 'mypath',
    component: MyComponent,
    resolve: {
        data: MyResolver
    }
}]);

А вот и компонент:

@Component({
    selector: 'my-component',
    template: '<Span>My Component</span>'
})
export class MyComponent implements OnInit {
    constructor(private route: ActivatedRoute) {
        console.log('component constructor');
    }

    ngOnInit(): void {
        console.log(this.route.snapshot.data['data']); // ['test1', 'test2', 'test3']
    }
}

Вероятно, это не лучший способ разработать взаимодействие между решением и службой, поэтому я очень открыт для предложений. Однако я могу сойти с ума, если не пойму, почему BehaviorSubject.asObservable () не работает, но имитируемый наблюдаемый объект работает.


person SnailCoil    schedule 21.02.2017    source источник
comment
В чем проблема? не работает нет информации.   -  person Günter Zöchbauer    schedule 21.02.2017


Ответы (3)


Я подумал об этом в одночасье и понял, что неправильно использовал разрешение. Суть проблемы в том, что маршрутизатор ожидает, что результат разрешения в конечном итоге будет завершен. BehaviorSubject, даже если он имеет только одно значение за раз, никогда не будет выполнен, потому что значение всегда может измениться. Я изменил this._data.asObservable() на this._data.asObservable().first(), и он начал работать. Теперь это кажется таким очевидным!

person SnailCoil    schedule 21.02.2017
comment
хм, похоже, не работает с angular 5, получается белый экран - person Иван Грозный; 16.11.2017

Чтобы Angular 6+ завершил наблюдаемое в резолвере, вам необходимо сделать следующее:

this.myService.getData().pipe(take(1))

// or

this.myService.getData().pipe(first())
person Timothy    schedule 03.08.2019
comment
Я не мог заставить это работать. Компонент на другом маршруте не получает отправленное событие от другого компонента. Нужен ли мне преобразователь для простого обмена данными между компонентами на разных маршрутах? - person Deepak Devanand; 09.04.2021