1

i have a problem with emiting values from behavior subject after switchMap operator from parent to child component. If i call real http API in console.log in child compoennt i only see empty array [] (default value), but in tap operator in parent component if i console.log data i saw array with 20 items, but in child component not. When i tried to make a mock service and return mocked data.

eg. return of(['item1', 'item2']

This case works fine, but when i only switched call service name, it doesn't work correctly for me, in tap i see data, but in child input not.

import { Component, VERSION } from '@angular/core';
import { BehaviorSubject, Subject } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { AppserviceService } from './appservice.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  name = 'Angular ' + VERSION.major;
  refresh$: Subject<void> = new Subject();
  data$: BehaviorSubject<string[]> = new BehaviorSubject<string[]>([]);

  constructor(private _appService: AppserviceService) {
    this.refresh$
      .pipe(switchMap(() => this._appService.test2()))
      .subscribe(res => {
        console.log('Subscribe:');
        console.log(res);
        this.data$.next(res)
      });

    this.refresh$.next();
  }
}


Child component

import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Component({
  selector: 'hello',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <h1>Hello {{ name }}!</h1>
  `,
  styles: [
    `
      h1 {
        font-family: Lato;
      }
    `
  ]
})
export class HelloComponent {
  @Input() name: string;
  @Input() set test(value: BehaviorSubject<any[]>) {
    console.log(value.getValue());
  }
}

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

Did you met with this issue ? Thanks.

Tom
  • 77
  • 7
  • try console log data before this line ```this.childData$.next(data);``` – Kartik Dolas May 23 '21 at 03:33
  • Try replacing ```refresh$ = new Subject();``` with ```refresh$ = new BehaviorSubject();``` – Kartik Dolas May 23 '21 at 03:41
  • When i console.log data, i saw results. And I think, behavior subject is not correct, because i don't need any default value. But i tried it with default null value and doesn't work too. There is an example on stackblitz. In service i have two API, one mock, second real API. Mock works fine, but second not. https://stackblitz.com/edit/angular-ivy-7wezwh?file=src/app/app.component.ts – Tom May 23 '21 at 04:07

1 Answers1

1

The reason is your child component gets instantiated before your http call completes. Right now you are only getValue()ing the first value. If you want the BehaviorSubject to emit new data every time it has one, you can fix this by simply adding the async operator:

<hello name="{{ name }}" [test]="data$ | async"></hello>
@Input() set test(value: any[]) {
  console.log(value);
}

Now every time the BehaviorSubject has a new value, it will be emitted to your child component

Fixed stackblitz

eko
  • 39,722
  • 10
  • 72
  • 98