1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Anuncie Aqui
    Anuncie aqui você Também: fdantas@4each.com.br

Angular BehaviorSubject emits twice when updating state used with ngModel and async pipe

Discussão em 'Angular' iniciado por UnderPhp, Julho 3, 2025.

  1. UnderPhp

    UnderPhp Guest

    I have an Angular(v20) standalone component that loads paged data from a server.

    I use a BehaviorSubject to manage query state (search text, category, pagination).

    Problem: Whenever I type even one character in the search input or change the category filter, two HTTP requests are sent instead of one.

    I added extensive console.log() statements to track the emissions:

    When typing a single letter, I see two emissions:

    [BEFORE debounceTime] query changed: ... [BEFORE debounceTime] query changed: ... This results in two HTTP calls (with identical parameters).

    I have already:

    Added debounceTime(300) before switchMap.

    Added distinctUntilChanged using lodash.isEqual.

    Ensured only one async pipe in the template.

    But still, two emissions happen.

    Code:

    Component TS (book-table.ts):

    this.books$ = this.query$.pipe(
    tap((query) => console.log('[BEFORE debounceTime]', query)),
    debounceTime(300),
    tap((query) => console.log('[AFTER debounceTime]', query)),
    distinctUntilChanged((prev, curr) => isEqual(prev, curr)),
    switchMap(({ search, category, pageIndex, pageSize }) =>
    this.bookService.getAll(pageIndex + 1, pageSize, search, category).pipe(
    tap(() => console.log('[API call triggered]')),
    map(res => res.items)
    )
    )
    );
    Component Template (book-table.html):

    <input
    matInput
    (input)="onSearchChange($any($event.target).value)"
    placeholder="Search"
    [ngModel]="query$.value.search"
    />

    <app-category-select
    [ngModel]="query$.value.category"
    (ngModelChange)="onCategoryChange($event)">
    </app-category-select>



    onSearchChange:

    onSearchChange(value: string) {
    this.query$.next({
    ...this.query$.value,
    search: value,
    pageIndex: 0,
    });
    }
    onCategoryChange:


    onCategoryChange(value: string) {
    this.query$.next({
    ...this.query$.value,
    category: value,
    pageIndex: 0,
    });
    }


    Observed Behavior:

    I type one character in the search input.

    query$.next() emits.

    Another emission happens right after.

    switchMap() is triggered twice, causing 2 HTTP calls.

    Question:

    Why are there two emissions when updating the query BehaviorSubject?

    Is it related to [ngModel]="query$.value.field" rebinding in the template?

    How should I structure my component and template to avoid this?

    Note: I have removed all additional combineLatest and multiple async pipe usages. Only one async pipe is present.

    Continue reading...

Compartilhe esta Página