Creating asynchronous functions in Angular is a vital component to optimize performance and improve user

Within componentOne.ts, I am sending data via the sharedService like this:

  this.sharedService.sendData(this.getCheckedProduct);

In componentTwo.ts, I am subscribing to the data in this manner:

      productList: any = [];

      getAllProducts: any = [];

      ngOnInit() {
        this.sharedService.getData().subscribe(data => {
          this.productList = data;
          this.getProduct();
        });
      }

Upon receiving the data in productList, I then call the function this.getProduct() which contains the following logic:

  getProduct() {
    let tempArray = [];
    this.productList.forEach(element => {
        this.appService.getRest(AppConfig.settings.product.getProducts + '/' + element.product_obj_id).subscribe(res => {
          tempArray.push(res.data);
        });
    });
    this.getAllProducts = tempArray;
  }

The objective is to pass the element.product_obj_id in order to retrieve the relevant data associated with that particular ID.

I attempted an alternate approach as follows:

  ngOnInit() {
    this.sharedService.getData().subscribe(data => {
      data.forEach(element => {
        this.getProduct(element);
      })
    });
  }

  async  getProduct(element) {
    let asyncResult = await this.appService.getRest(AppConfig.settings.product.getProducts + '/' + element.product_obj_id).toPromise();
    this.getAllProducts.push(asyncResult['data']);
  }

Although the data is successfully retrieved inside the async getProduct(element) function, I encounter issues displaying it in the HTML portion of the code:

HTML:

<div *ngFor="let product of getAllProducts">
 Getting data
</div>

Switching to an async implementation results in an error:

<div *ngFor="let product of getAllProducts | async">
 Getting data
</div>

The error message is:

ERROR Error: InvalidPipeArgument: '' for pipe 'AsyncPipe'
    at invalidPipeArgumentError

To elaborate, the main goal is to send data from componentOne through sharedservice, receive it in componentTwo, extract the product_obj_id from the received data, and subsequently fetch and store the final data from the service request. The ultimate aim is to populate the getAllProducts array with the acquired data.

AppConfig.settings.product.getProducts 

represents the URL endpoint.

The challenge lies in effectively handling the data asynchronously, ensuring that the getAllProducts array is populated with the final data fetched from the service call for each ID passed.

this.getAllProducts.push(asyncResult['data']);

works within the function but the retrieved value seems to be inaccessible outside the function, rendering getAllProducts ineffective in the HTML section.

Previously, in scenario 1, I used:

this.getAllProducts = tempArray;

This method resulted in an empty array, prompting the shift to the async approach.

In essence, the goal is to obtain the final data within this.getAllProducts from the service, where an ID passed in the URL fetches the required information.

Answer №1

To incorporate your data into the async call, you can follow this method:

fetchProducts() {
    let productList = [];
    this.productsList.forEach(item => {
        this.apiService.get(ApiConfig.settings.product.fetchProducts + '/' + item.id).subscribe(response => {
          productList.push(response.data);
          this.updatedProductList = productList; // This line here
        });
    });
  }

Note: It is not necessary to use the async pipe in your situation.

Answer №2

AsyncPipe should only be used with an Observable. It seems in your case, you are applying it to getAllProducts which appears to be an Array. This mismatch is likely causing the error you are encountering.

Here is a possible solution:

  1. Remove the async directive from your loop that iterates over getAllProducts
  2. Ensure that getAllProducts returns an Observable of your products

Given that you are iterating through your productList and making API calls for each product, you may need to utilize the mergeMap operator.

Consider using Solution 2, as it seems more tailored to your scenario, where productList requires individual API calls to retrieve product details.

Learn about MergeMap here

Refer to the following sample code (untested, and error handling with catchError needs to be implemented):

import { from } from 'rxjs';
import { mergeMap, map, combineAll } from 'rxjs/operators';

this.getAllProducts = from(this.productList)
    .pipe( 
        mergeMap(element =>
            this.appService.getRest(AppConfig.settings.product.getProducts + '/' + element.product_obj_id).pipe(
                map(res => res['data'])
            )
        ),
        combineAll()
    )

<div *ngFor="let product of getAllProducts | async">
    Retrieving data
</div

Explanation:

Given that your productList is an array, and you need to make individual requests for each product object, using mergeMap allows you to achieve this by firing a request for each product within the array. This is why you see

this.appService.getRest(AppConfig.settings.product.getProducts + '/' + element.product_obj_id)
inside the mergeMap. The response from the API is then mapped using map, and finally aggregated using combineAll to return an Observable<[]> stored in getAllProducts, making it suitable for use with AsyncPipe.

Edit:

Add the following code in your constructor rather than in ngOnit

const getAllProducts = this.sharedService.getData().pipe(
  mergeMap(data=> from(data))
).pipe( 
    mergeMap(element =>
        this.appService.getRest(AppConfig.settings.product.getProducts + '/' + element.product_obj_id).pipe(
            map(res => res['data'])
        )
    ),
    combineAll()
)

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

Validating Forms using Javascript

I'm struggling to understand why I'm not getting any error or success messages when I click the submit button. My goal is to validate strings in an HTML form to ensure they are not null or too long. Both the developer's tools and the Online ...

Utilizing interpolation within various function invocations

componentDidMount() { let env = clientConfiguration['Environment']; let x = `communitiesApi.${env}`; fetch(clientConfiguration[x]) .then((response) => { return response.json(); }) .then(data =& ...

Struggling to increment the badge counter in a React Typescript project

I'm a bit unsure about where to apply the count in my Badge Component. The displayValue should include the count, but I'm struggling with how to implement it. UPDATE: The counter is now in place, but when I decrease the count and it reaches 0, t ...

What is the most efficient way to prevent duplicate items from being added to an array in a Vue 3 shopping cart

I currently have a functional shopping cart system, but I am facing an issue where it creates duplicates in the cart instead of incrementing the quantity. How can I modify it to only increment the item if it already exists in the cart? Also, I would like t ...

Concerns with JavaScript Scope

I'm currently working on a function that I need help with. The function seems pretty straightforward to me: function CheckFile(path){ var status = false; $.ajax({ url: "http://mydomain.com/"+path, type: "HEAD", s ...

Creating a new web application, I require a loading overlay to appear during transitions between pages

I've checked high and low, but I can't seem to find the solution! My webapp has a page that is bogged down with data causing it to load slowly. Is there a way to display a loading div while transitioning to the next page? Perhaps something like ...

Adding additional properties to Material UI shadows in Typescript is a simple process that can enhance the visual

https://i.stack.imgur.com/9aI0F.pngI'm currently attempting to modify the Material UI types for shadows, but encountering the following error when implementing it in my code. There is no element at index 25 in the tuple type Shadows of length 25. I&a ...

Unable to invoke requestPointerLock() function within Vue.js component

Incorporating the requestPointerLock() method within a Vue.js component has posed some challenges for me. In the scenario where the pointerShouldLock data property of my component is set to true, I intend for the pointer to be locked during the beforeUpdat ...

Issue with scrollTop not functioning when using onclick on an <a> tag within a div

After various attempts and research online, I am still experiencing erratic scrolling behavior with the scrollTop function. My goal is to scroll within a specific div when clicking on links. The content of my div: <div id="test" style="height:400px; o ...

Update a variable in one component class using another component

My Hue class in a component contains a variable that I'm trying to modify: export default class Hue extends Component { state = { toggleState : false, toggleWhite : false } render(){...} ... } Within this component, I can chang ...

How to handle multiple formData input in NestJS controller

How can I create a controller in Nest.js that accepts two form-data inputs? Here is my Angular service code: public importSchema(file: File, importConfig: PreviewImportConfig): Observable<HttpEvent<SchemaParseResponse>> { const formData = ...

Is it possible to trigger an ajaxcall once another one has finished executing?

Just curious, do you think the code snippet below is capable of triggering a second ajax function once the first one has completed successfully? if(xmlHttp) // xmlHttp represents an XMLHttpRequest object { xmlHttp.onreadystatechange = function() ...

What is the best way to combine the elements of two arrays within a v-for loop?

Within my code, I have defined two arrays: users and projects. Each array contains unique numbers as IDs. A project can be owned by multiple users, so in the projects array, there is an array of user IDs named ownersId that corresponds to the id of users i ...

Strategies for Sorting Nested Arrays in JavaScript

Here is the JSON data I have: { "list": [ { "deviceId": "2a-d539-4031-9bfc-4a42f2f765cf", "versions": [ { "id": "764c20-a213-9235f4b553b3", "createdTime": 1590361208034, "files": [ { ...

The Angular Material Tree component is not rendering properly in an Angular tutorial demonstration

Upon completing the installation of @angular/material, @angular/cdk, and @angular/animations through npm install --save, I attempted to reconstruct the flat tree example provided by Angular. Unfortunately, even after addressing the error message stating Co ...

Error encountered: The property 'localStorage' is not found on the 'Global' type

Calling all Typescript enthusiasts! I need help with this code snippet: import * as appSettings from 'application-settings'; try { // shim the 'localStorage' API with application settings module global.localStorage = { ...

Improving Angular component performance with a multitude of subcomponents

Some time back, I created a grid component for an Angular application. Each Grid consists of rows represented by Row components, and each Row contains cells that are also components called Cell. These cells can hold various "objects" which are essentially ...

Ensuring the model accurately reflects the input's value attribute in AngularJS

I am in the process of creating a set of image "radio buttons" where only one can be selected per group. However, as a newcomer to Angular, I'm facing difficulties in maintaining the value and using it as my ng-model. Additionally, I am looking for a ...

Navigating through intricate JavaScript object

I need help figuring out how to access the "description" property of a JSON object I received from an API endpoint. The object looks like this: - "description" : "Dorian Market 1"? let markets = { "result":[ { "townId" : "MEBD", "stor ...

Utilizing autosuggest in combination with jQuery ajax consistently generates suggestions with a delay of 1 keystroke

I'm currently working on creating an autosuggest feature for a search box, but I've run into a problem. The suggestions that are displayed don't seem to match the current keystroke input (they keep showing suggestions based on the previous k ...