Preventing unnecessary API requests in Angular 9 when using typeahead functionality

Currently, I'm working on integrating a search box feature that needs to trigger an API call when the user enters a value. The goal is to initiate the call after the user stops typing for a certain amount of time.

The initial request setup is functioning correctly:

this.searchForm.get('searchQuery').valueChanges.pipe(
  filter(data => data.trim().length > 0),
  debounceTime(500),
  switchMap( (query: string) => this.productsService.searchProducts(query))
).subscribe();

However, during continuous typing, the system seems to be waiting for another 500ms and then sending multiple requests (equivalent to the number of characters typed).

productsChanged = new Subject<Product[]>();

  searchProducts(query: string) {
    return this.http.get<Product[]>(this.baseUrl + '/products/search/' + query)
        .pipe(
          tap(products => {
            this.products = products;
            this.productsChanged.next(this.products.slice());
          }));
   }

I suspect it might be a simple fix, but I am struggling to identify what exactly is causing this behavior.

For reference, here is the Stackblitz link: https://stackblitz.com/edit/angular-ivy-w4mbhm


Solution

After some investigation, I have located the issue.

The problem stemmed from my setup listening to (ngModelChange):

  <input
name="searchQuery" 
type="text" 
[(ngModel)]="searchQuery"
(ngModelChange)="onSearch()"
formControlName="searchQuery" />

Within that listener, I inadvertently appended a new listener to 'valueChanges' each time, resulting in the creation of additional listeners upon every keystroke.

A straightforward mistake that led me to spend hours troubleshooting.

Thank you for your assistance!

Answer №1

It seems that you are continuously subscribing to changes in your form, which may not be necessary. Consider subscribing only once in your component, or better yet, utilize the async pipe:

Check out this working example

ngOnInit(): void {
  this.searchForm = new FormGroup({
    searchQuery: new FormControl()
  });

  this.searchForm
    .get("searchQuery")
    .valueChanges.pipe(
      // filtering and debouncing logic
    )
    .subscribe((e) => {
      console.log(e)
    });
}

Alternatively, you can simplify it by doing:

ngOnInit(): void {
  this.products$ = this.searchForm.get("searchQuery").valueChanges.pipe(
    // ...
  )
}

You can then use the async pipe approach, eliminating the need to manually unsubscribe on destroy.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Looking to individually check each query parameter in Angular 6?

I'm currently struggling with managing query parameters in my Angular application. There are multiple query parameters on my search page with the following URL: /search?q=hyderbard&view=map&type=bat&brand=sg const urlParams = Observab ...

Oops! The program encountered an issue where it couldn't access the "Point" property because it was undefined. This occurred while working with openlayers 3 and jsts on

I am currently working on implementing a buffer function for some features that have been drawn on a map following this particular example. However, I am encountering the following error: ERROR TypeError: Cannot read property 'Point' of undefin ...

Dynamically altering the CSS4 variables in real time

I am facing the challenge of managing multiple CSS4 variables, including primary, for various companies. How can I dynamically change the primary CSS4 variable color based on the company? Note: My specific requirement is to update the primary variable glo ...

Steps to Solve Uncaught Error: Template parse errors: Element 'nb-sidebar' is not recognized:

Just starting out with Nebular, I'm curious if there are any comprehensive Nebular documentation available? I've attempted to add a component within a module. Specifically, I created a sidebar component within a sidebar module. App.module i ...

What is the best way to refresh the snapshots in my React/TypeScript project?

I am working on a React/TypeScript project that utilizes the Jest testing framework. Occasionally, after making changes to my code, Jest will compare it to the snapshots and generate an alert requesting me to update them. However, there are instances where ...

Attempting to utilize Array Methods with an Array Union Type

Currently, I am in the process of refactoring an Angular application to enable strict typing. One issue I have encountered is using array methods with an array union type in our LookupService. When attempting to call const lookup = lookupConfig.find(l =&g ...

Tips for handling datetime in angular

Currently, I am working with Angular (v5) and facing an issue related to Datetime manipulation. I am trying to retrieve the current time and store it in a variable. After that, I need to subtract a specified number of hours (either 8 hours or just 1 hour) ...

Experience the magic of live streaming with our cutting-edge technology bundle featuring RTSP streaming, AspNet 5 API integration, FFM

Description: I am working on an API (ASP.Net 5) that connects to an IP Camera through RTSP. The camera sends a h264 stream converted with ffmpeg as an m3u8 stream, which is then returned to the Angular client in the following manner: public async Task< ...

Issue with displaying modal and backdrop specifically on iPhone in Angular 13

Within our Angular 13 application, we have a modal component. The component's CSS includes the :host selector for the root element, which also serves as the style for the backdrop: :host { position: absolute; background: rgba(0, 0, 0, 0.5); widt ...

When working with Typescript, it is important to correctly identify elements as checkboxes in order to avoid any red underlines when referencing

When trying to check the input type of an element, such as a checkbox in TypeScript, I encounter the issue of the 'element.checked' property being underlined in red. The code snippet below shows how I attempt to address this: element: HTMLElemen ...

Angular: Comparing the Performance of Switch Statements and Dictionary Lookups

Having trouble deciding between two options for parsing URL parameters? Both seem suboptimal, but is there a better way to handle this situation? If you have any suggestions for a plausible Option #3, please share. Let's assume we are dealing with up ...

Discovering the ReturnType in Typescript when applied to functions within functions

Exploring the use of ReturnType to create a type based on return types of object's functions. Take a look at this example object: const sampleObject = { firstFunction: (): number => 1, secondFunction: (): string => 'a', }; The e ...

What is the best way to manage data that arrives late from a service?

Within my Angular application, I have a requirement to store data in an array that is initially empty. For example: someFunction() { let array = []; console.log("step 1"); this.service.getRest(url).subscribe(result => { result.data.forEach( ...

Preventing dynamically generated components from reinitializing upon adding a new object

Within my application, there is a unique feature where components are dynamically generated through a *ngFor loop. Here is an example of how it is implemented: <div *ngFor="let actionCategory of actionCategories | keyvalue"> <h2>{ ...

Implement Angular backend API on Azure Cloud Platform

I successfully created a backend API that connects to SQL and is hosted on my Azure account. However, I am unsure of the steps needed to deploy this API on Azure and make it accessible so that I can connect my Angular app to its URL instead of using loca ...

The error message encountered while using webpack with TypeScript and React is: "Unexpected token React.Component

I am currently working on setting up a project using webpack, typescript, and react. I have implemented babel to transpile my typscript/react code. However, when starting the development server, I encountered the following error: Module parse failed: Un ...

The issue with Angular2 Material select dropdown is that it remains open even after being toggled

Exploring the world of Node.js, I am delving into utilizing the dropdown feature from Angular Material. However, an issue arises once the dropdown is opened - it cannot be closed by simply clicking another region of the page. Additionally, the dropdown lis ...

Error in NextJS: The name 'NextApplicationPage' cannot be found

const { Component, pageProps}: { Component: NextApplicationPage; pageProps: any } = props After implementing the code above with 'Component' type set to NextApplicationPage, an error message pops up stating, The name 'NextApplicationPage&ap ...

What is the best way to organize a material table with favorites prioritized at the top?

My goal was to customize the sorting of a mat-table in Angular, ensuring that the "favorite" items always appear at the top of the table. I aimed for the favorite items to maintain their position as the first items in the table regardless of any other sor ...

Express is encountering an issue where it is unable to interpret the property 'name' of an undefined element coming from

I am attempting to create a fullstack application using Node.js and Angular with Material UI. I have encountered an issue while working on my web resource management application. Currently, I am facing an error during the registration and data submission ...