Observable не подписывается на ленивый загруженный модуль - PullRequest
0 голосов
/ 21 марта 2020

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

index.ts

export { TestComponent } from './test.component';
export { TestModule } from './test.module';

test.component.ts

import { Component, OnInit } from '@angular/core';
import { TestService } from './test.service';
import { Observable } from 'rxjs';

@Component({
    selector: 'test',
    template: `
        <p>{{test | async}}</p>
  `,
})
export class TestComponent {
    test: Observable<number>;
    constructor(private testService: TestService) { 
        this.test = this.testService.getObservable();
    }
}

test.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TestComponent } from './test.component';
import { TestService } from './test.service';

@NgModule({
    declarations: [TestComponent],
    imports: [
        CommonModule,
    ],
    providers: [TestService]
})
export class TestModule { }

test.service.ts

import { Injectable } from '@angular/core';
import { from, Observable } from 'rxjs';
import { delay } from "rxjs/operators";

@Injectable()
export class TestService {
    getObservable(): Observable<number> {
        return from([...Array(10).keys()].reverse())
            .pipe(
                delay(1000)
            )
    }
}

app.component.ts

import { Component, ViewChild, ViewContainerRef, Compiler, Injector, Type, NgModuleFactory } from '@angular/core';
import { TestModule } from './test';

@Component({
    selector: 'app-root',
    template: `
        <ng-container #vc></ng-container>
  `,
    styles: []
})
export class AppComponent {
    @ViewChild('vc', { read: ViewContainerRef }) containerRef: ViewContainerRef;

    constructor(private compiler: Compiler, private injector: Injector) {
    }

    async ngOnInit(): Promise<void> {
        await this.loadComponent();
    }

    async loadComponent(): Promise<void> {
        const { TestComponent, TestModule } = await import('./test');
        const moduleFactory = await this.loadModuleFactory(TestModule);
        const moduleRef = moduleFactory.create(this.injector);
        const factory = moduleRef.componentFactoryResolver.resolveComponentFactory(TestComponent);
        this.containerRef.createComponent(factory);
    }

    private async loadModuleFactory(moduleFactory: Type<TestModule>): Promise<NgModuleFactory<TestModule>> {
        if (moduleFactory instanceof NgModuleFactory) {
            return moduleFactory;
        } else {
            return await this.compiler.compileModuleAsync(moduleFactory);
        }
    }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }

app.module.ts здесь только для полноты.

Когда весь этот код скомпилирован, текст между * 1037 Тег * p не отображается.

Ответы [ 2 ]

0 голосов
/ 24 марта 2020

Исходя из вашего исходного примера, что-то вроде этого будет работать:

  numbers$: Observable<number> = from(
    Array.from(Array(10).keys()).reverse()
  ).pipe(
    concatMap(n => of(n).pipe(delay(1000))),
    tap(console.log)
  );

Несколько вещей:

В TypeScript я не мог использовать оператор распространения из-за этого: https://github.com/Microsoft/TypeScript/issues/18247

Оператор задержки задерживает начало выброса, а не интервал между выбросами.

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

С точки зрения читабельности кода предложенный вами альтернативный подход кажется более ясным:

  numbers$ = interval(1000).pipe(
    take(10),
    map(time => 9 - time)
  );
0 голосов
/ 21 марта 2020

Ну, в конечном итоге, причина, по которой я не получил результат моего предполагаемого наблюдаемого обратного отсчета, - это всего лишь вещь rx js. Я не могу понять, почему мой подход не работает:

from([...Array(10).keys()].reverse()).pipe(delay(1000));

Для меня это был бы интуитивно понятный способ создания обратного отсчета. После небольшого исследования стека overoverflow я выяснил, как заставить его работать правильно. Как это:

const timer = 10; 
interval(1000).pipe(take(timer), map(time => (timer - 1) - time));
...