Изменение источника потока - PullRequest
1 голос
/ 15 марта 2019

В angular у меня есть абстрактный класс, который отвечает за изменение параметров запроса:

@Injectable()
export abstract class PageDetailsAbstract<T> implements OnInit {
  object: string;
  id: number;
  details$: Observable<T>;

  constructor(
    protected entitiesSelectors: EntitiesSelectors) {
  }

  ngOnInit() {
    this.route.params
      .pipe(
        map(resp => +resp.id),
      )
      .subscribe(resp => {
        this.id = resp;
        this.adopt();
      });
  }

  protected adopt() {
    if (this.id) {
      this.details$ = this.entitiesSelectors.details(this.object, this.id);
    }
  }
}

У меня есть также конкретный класс для страницы сведений:

@Component({
  selector: 'app-page-maile-szczegoly',
  templateUrl: './page-maile-szczegoly.component.html',
  styles: [],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PageMailsDetailComponent extends PageDetailsAbstract<Mail> {
  object = 'mails';
  // ...

  ngOnInit() {
    super.ngOnInit();
    this.details$
      .subscribe(data => {
        // do something with it
        // it's triggered only once
      });
  }
}

Проблема в том, что subscribeв ngOnInit срабатывает только один раз.Это из-за this.details$ = this.entitiesSelectors.details(this.object, this.id); в родительском классе.Экземпляр this.detials$ уничтожается, и с его помощью subscribe функция.

Как может иметь всегда один и тот же экземпляр this.details$, но всегда исправлять один с this.entitiesSelectors.details(this.object, this.id)?

1 Ответ

1 голос
/ 15 марта 2019

вы можете использовать Subject (http://reactivex.io/rxjs/class/es6/Subject.js~Subject.html)

Я создал очень упрощенный стек, чтобы показать, как он работает https://stackblitz.com/edit/angular-zyvkpu?file=src%2Fapp%2Fapp.component.ts

см. Вывод консоли для проверки.

здесь соответствующая часть кода (адаптирована к вашему случаю, а не 1: 1 от stackblitz)

@Injectable()
export abstract class PageDetailsAbstract<T> implements OnInit {
  object: string;
  id: number;
  details$: Subject<T> = new Subject<T>();

  constructor(
    protected entitiesSelectors: EntitiesSelectors) {
  }

  ngOnInit() {
    this.route.params
      .pipe(
        map(resp => +resp.id),
      )
      .subscribe(resp => {
        this.id = resp;
        this.adopt();
      });
  }

  protected adopt() {
    if (this.id) {
      this.entitiesSelectors.details(this.object, this.id).subscribe((detail: T) => {
        this.details$.next(detail);
    });
  }
}

лично я бы немного перестроил код. это очиститель ставок, потому что вы не будете вкладывать несколько звонков на subscribe и не будете полагаться (по крайней мере, не так сильно) на this.id, который существует вне потока rxjs.

до

@Injectable()
export abstract class PageDetailsAbstract<T> implements OnInit {
  object: string;
  id: number;
  details$: Subject<T> = new Subject<T>();

  constructor(
    protected entitiesSelectors: EntitiesSelectors) {
  }

  ngOnInit() {
    this.route.params
      .pipe(
        mergeMap((resp: any) => {
         return this.adopt(+resp.id);
      }))
      .subscribe((detail: T) => {
        this.details$.next(detail);
      });
  }

  protected adopt(id: number): Observable<T> {
    if (this.id) {
      return this.entitiesSelectors.details(this.object, this.id);
    }
    else {
      return of(null); // or whatever is appropriate in your case (e.g. EMPTY or something)
    }
}

ваш дочерний класс останется прежним.

почему
почему ваш пример не работает: Я думаю, что это потому, что details$ - наблюдаемая холодность. (https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html)

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

Subject является горячей наблюдаемой. Возможно, вы могли бы также использовать что-то вроде publish или share, чтобы преобразовать вашу холодную наблюдаемую в горячую.

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