Weird behavior of BehaviorSubject, async pipe, and *ngIf combination: ngOnChanges receives the change that theoretically cannot be possible

I have two components – Parent component which fetches the data from the server, and child component which is displaying fetched entries as a list – but only if the list is not null or empty.

My problem is (short): Even if there is *ngIf checking that the list has some values, emission is done and in child component I get first emission with null items: ![First emission] (

Second emission is though okay… ![Secod emission] (

Does somebody have an idea?

The parent component also contains search field where you can search entries. Here is the code:

<lookup-area [debounceTime]="100"

<app-virtual-list *ngIf="(channels$ | async)?.length > 0"
                  [items]="channels$ | async"
                  [maxContainerHeightPx]="190 - ((channels$ | async)?.length ? 29 : 0)"
    <ng-template let-item>Some template</ng-template>
             selector: 'app-filter',
             templateUrl: './filter.component.html',
             changeDetection: ChangeDetectionStrategy.OnPush,
             encapsulation: ViewEncapsulation.None
export class FilterComponent implements OnInit, OnDestroy {

    public search$ = new BehaviorSubject('');

    constructor(private service: YoutubeSearchService) {

    public ngOnInit(): void {
        this.channels$ = combineLatest([this.service.getYoutubeChannels(),$]).pipe(
            map(([channels, search]) => search ? channels.filter(channel => ( || : channels),
            map(channels => channels?.sort((a, b) => ( || ||, undefined, { sensitivity: 'base' })))

    public ngOnDestroy(): void {$.complete();

    public searchChanged(search: string): void {$.next(search);

    public trackByFn(index: number, item: YoutubeChannel): any {


And the child component contains the logic for displaying. Here is the code:

             selector: 'app-virtual-list',
             templateUrl: './virtual-list.html',
             styleUrls: ['./virtual-list.less'],
             changeDetection: ChangeDetectionStrategy.OnPush,
             encapsulation: ViewEncapsulation.None
export class VirtualList<T> implements OnChanges {

  // Mandatory
  @Input() public items: T[];
  @Input() public itemHeightPx: number;

  // Optional
  @Input() public maxContainerHeightPx: number | undefined; // If undefined, scroll container's height is 100%

  public ngOnChanges(changes: SimpleChanges): void {
      const { items, itemHeightPx, maxContainerHeightPx } = changes;

      if (this.maxContainerHeightPx && (items || itemHeightPx || maxContainerHeightPx)) {


I tried:

  1. wrapping everything in <ng-container *ngIf="(channels$ | async)?.length > 0">, but no success
  2. wrapping in another div, still did not work

I have no clue what else to try because it seems that *ngIf does not work which is really weird.

I would expect that the first change comes with the items inside since that is what *ngIf is telling.

>Solution :

Not sure I understand your issue, but I already see a bad thing in your code, so try to resolve it and see if the issue persists.

You don’t need to create 3 subscriptions, a single one is enough.

<ng-container *ngIf="channels$ | async as channels">
    [maxContainerHeightPx]="190 - (channels?.length ? 29 : 0)"
    <ng-template let-item>Some template</ng-template>

Leave a Reply