Почему комбинированные наблюдаемые не обновляют шаблон при использовании Subject или если они излучают после ngAfterContentInit - PullRequest
0 голосов
/ 07 февраля 2019

Я определяю наблюдаемое (result $) в компоненте и отображаю его в шаблоне через асинхронный канал.Наблюдаемая - это комбинация двух других наблюдаемых (первая $, вторая $) с помощью combLatest.Если одна из наблюдаемых или обе из них выдают слишком рано (до того, как я обнаружил ngAfterContentInit), результирующая наблюдаемая не будет выдавать значение.

Компонент: не работает

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

result$: Observable<number>;
first$ = new Subject<number>();
second$ = new Subject<number>();

  constructor() {}

  ngOnInit(){
      this.result$ = combineLatest(
        this.first$,
        this.second$
      ).pipe(
        map(([first, second]) => {
          // This is not printed to the console
          console.log('combined obs emitted value');
          return first + second;
        })
      );
   console.log('first and second emit value');
   this.first$.next(2);
   this.second$.next(4);
  }

  ngAfterContentInit() {
      console.log('ngAfterContentInit');
  }
}

Порядок выполнения:

1-е и первое значение излучения

2.ngAfterContentInit

Здесь я предполагаю, что в ngAfterViewInit шаблон был отображен, а подпискибыло сделано.Поскольку наблюдаемые передают значение до этого, компонент не уведомляется.Это может означать только то, что результирующая наблюдаемая является холодной (поэтому вам необходимо подписаться, прежде чем она выдаст значение).2 наблюдаемые являются субъектами, поэтому я предполагаю, что субъекты являются холодными наблюдаемыми.Это правильно?

Если я задерживаю эмиссию первых $ и вторых $, все работает: Component: first $ и second $ emit позже @Component ({selector: 'my-app', templateUrl: './app.component.html ', styleUrls: [' ./app.component.css ']}) класс экспорта AppComponent {

result$: Observable<number>;
first$ = new Subject<number>();
second$ = new Subject<number>();

  constructor() {}

  ngOnInit(){

      this.result$ = combineLatest(
        this.first$,
        this.second$
      ).pipe(
        map(([first, second]) => {
          console.log('combined obs emitted value');
          return first + second;
        })
      );

    // Solution 1: add timeout
    setTimeout(() => {
      console.log('first and second emit value');
      this.first$.next(2);
      this.second$.next(4);
    })

  }

  ngAfterContentInit() {
      console.log('ngAfterContentInit');
  }
}

Порядок теперь:

  1. ngAfterContentInit

  2. первое и второе значения излучения

  3. комбинированное значение излучения obs

Такопять же, это потому, что подписка сделана до того, как наблюдаемые передадут значение?

Если я изменю наблюдаемые на BehaviorSubject, все тоже будет работать, даже если значения генерируются до того, как подписка произойдет.Означает ли это, что поведенческие объекты являются горячими наблюдаемыми?Компонент: работает

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

result$: Observable<number>;
first$ = new BehaviorSubject<number>(0);
second$ = new BehaviorSubject<number>(0);

  constructor() {

  }

  ngOnInit(){

this.result$ = combineLatest(
        this.first$,
        this.second$
      ).pipe(
        map(([first, second]) => {
          // This is not printed to the console
          console.log('combined obs emitted value');
          return first + second;
        })
      );


  console.log('first and second emit value');
   this.first$.next(2);
   this.second$.next(4);


  }

  ngAfterContentInit() {
      console.log('ngAfterContentInit');
  }
}

Stackblitz

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Используйте BehaviorSubjects вместо Subjects

https://stackblitz.com/edit/angular-4gnxto?file=src/app/app.component.ts

Асинхронный канал подписывается после того, как Subject отправлены.BehaviorSubjects дают последний результат, когда вы подписываетесь, субъекты дают вам только то значение, которое они излучают.

Когда асинхронный канал подписывается на результат $ observable, созданный с помощьюlateLatest, он не будет выдавать никакого значения из уже выданных объектов, он будет объединять только последние для субъектов, которые испускаются после подписки.

Посмотрите, как в этом StackBtitz

https://stackblitz.com/edit/angular-eb7dge?file=src/app/app.component.ts

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

0 голосов
/ 07 февраля 2019

Q1: 2 наблюдаемые являются субъектами, поэтому я предполагаю, что субъекты являются холодными наблюдаемыми.Это правильно?

A1: ответ на этот вопрос говорит о том, что тема сама по себе горячая.Эта статья описывает горячие, холодные и темы.

Q2: И снова, это происходит потому, что подписка осуществляется до того, как наблюдаемые издают значение?

A2: Да.Подписка на тему будет получать значения после подписки.Введенная вами задержка () должна была дать время, чтобы это произошло.

Почему? Это потому, что BehaviorSubject всегда содержит значение и выдает его при подписке, а Subject не содержит значения, он просто передает значения от производителя текущим подписчикам. Подробности .

В3: Означает ли это, что поведенческие объекты являются горячими наблюдаемыми?

A: См. A1.

Извинения, если это не дает прямого ответа на ваш вопрос,Я просто пытаюсь сказать, что ... когда я имею дело с Subject и BehaviorSubject, мне все равно, горячие они или холодные.

Вместо этого я спрашиваю: «Хочу ли я, чтобы наблюдаемое всегда держалозначение, когда я подписываюсь?Если да, я использую BehaviorSubject.Если у меня все в порядке без значения при подписке, тогда Subject в порядке.Помимо этой разницы, они оба будут получать испущенные значения после подписки.--- зависит от вашего варианта использования.

...