Employing async await for postponing the execution of a code block

I have been working on an Angular component where I need to perform some actions after a data service method returns some data asynchronously. Although I attempted to use async/await in my code, I feel that I may not have fully understood how it works. Here is the method I have implemented in the component:

async redrawGrid(params: any) {
        let v;
        try {
            v = await this.innerGridService.loadAccountList()
        } catch (error) {
            // handle error
        }
        
        params.node.childFlower.setRowHeight((this.globalRowCount * 46) + 48);
        this.gridOptions.api.onRowHeightChanged();
}

The loadAccountList() method in my service returns an observable:

...
@Injectable()
export class ClientListService { 
...
responseObject$: Observable<ResponseObject>;
...

}
loadAccountList() {
    this.logService.info('InnerGridService loadAccountList()');

    if (this.dataStore.responseObject) {
        this.refreshDataStore();
    }
    let token = this.authenticationService.getToken();
    let headers = new Headers({ 'netx.esf.AuthenticationService': token });
    let options = new RequestOptions({ headers: headers });

    this.http.get(`${this.baseUrl}`, options)
    .map((response: Response) => response.json())
    .subscribe(
    (data: InnerGridResponse) => {
        this.formatData(data.response.accountlist);
        this.dataStore.InnerGridResponse = data;
        this.dataStore.responseObject = data.response;
        this._InnerGridResponse.next(Object.assign({}, this.dataStore).InnerGridResponse);
        this._responseObject.next(Object.assign({}, this.dataStore).responseObject);
        if (data.errorCode === 0 || data.errorCode === 90) { // success
            this.logService.info('loadAccountList() success: ', data.errorCode);
            this.clearError();
        } else { // error code from backend
            this.logService.error('loadAccountList() errorCode: ', data.errorCode);
            this.setError(this.message[0], data.errorCode);
        }
    },
    error => { // exception
        this.logService.error('loadAccountList() exception:', error);
        this.setError(this.message[0], error._body);
        // throw error;
    });

    return this.responseObject$;
}

Answer №1

I must admit, the code you've shared here is in need of some major restructuring.

You seem to be stuck in a classic anti-pattern where data is being transferred from one stream to another, akin to pouring water from a hose into a bucket and then attempting to pour that water back into another hose. It would be more efficient to simply connect the hoses together or just pass on the original hose to someone else.

In simpler terms, a service should ideally not subscribe to an observable and perform operations on it. Instead, it should just return the observable, usually after some mapping. The actual subscription should take place in the consumer (the component), either within the TypeScript logic or in the template using the async pipe.

Without fully grasping the details of your service, I won't attempt to rewrite it all. However, the fundamental structure should resemble something like this:

locaAccountList(): Proimse<AccountList> {
  return this.http.get(URL)
    .map(response => response.json())
    .toPromise()
    .then(json => makeAccountListFromJson(json));
}

In my revision, I've modified the function to return a promise instead of an observable by utilizing toPromise. This approach is commonly used with this.http since it typically returns an observable with only one emission. By doing so, you can use await to wait for the result as opposed to waiting for an observable to emit. Remember, await works with promises, not observables.

After reformatting your service, the corresponding component can execute functions like so:

async redrawGrid(params: any) {
  await this.innerGridService.loadAccountList();

  // Code to be executed post loadAccountList() data retrieval
  params.node.childFlower.setRowHeight( (this.globalRowCount * 46 ) + 48);
  this.gridOptions.api.onRowHeightChanged();
}

The try block may not be necessary since errors within an async function will naturally propagate down and result in a rejected promise at the end. Furthermore, it's not entirely clear how you intend to utilize the outcome of invoking loadAccountList().

Answer №2

To delay the process until the data is fetched, relocate the subscription from the service to the redrawGrid function and insert the necessary code inside the subscribe callback.

Answer №3

An easy solution to this problem is as follows:

async updateGridDisplay(parameters: any) {
        let result;
        try {
            // take note of the .toPromise() method
            result = await this.gridService.fetchData().toPromise();
        } catch (error) {
            // handle errors here
        }
        // Code that needs to run after fetching data from fetchData()
        parameters.node.updateRowStyle( (this.totalRowCount * 46 ) + 48);
        this.dataGridOptions.api.onRowHeightChanged();
}

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

What is the best way to link the value of a mat-slider to an input field in a reactive form?

Is there a way to synchronize the min and max values of a ranged mat-slider with corresponding input fields? Currently, when I set numbers in the input fields, the slider updates correctly. However, when I use the slider to change the value of the input fi ...

Webpack 5 is failing to bundle re-exports correctly

Whilst bundling my web application, I've come across an issue with re-exports of certain modules not behaving as expected. Despite trying various optimization settings, I have been unsuccessful in resolving this issue. Setup Here's the setup tha ...

Enhance your production bundle in Angular CLI 7 by incorporating defer/async attributes

Recently, I have been experiencing some performance issues with a new site built using Angular CLI 7, particularly when accessed through mobile browsers. Upon further investigation, I pinpointed the main cause of the poor performance to be the absence of p ...

Cannon-js: Experience dynamic body bouncing on the y axis as it reacts to force applied on the x and z axes

Currently, I am working on an FPS game where the player controller applies force based on keyboard inputs to a dynamic cannon body. The angular dampening is set to 1 on the player body. The PlayerController class takes both the player class (which extends ...

Updating Firebase token in Angular when it has expired

Currently working on a website using Angular, I have integrated the Firebase SDK for email/password authentication. The main aim is to automatically generate a new token if the user closes the site and returns after a week. However, I am unsure which func ...

TypeScript version 3.7 has implemented a new feature where it will now display errors for each individual invalid prop instead of grouping them together as it

Scenario using TypeScript 3.5.3 https://i.stack.imgur.com/wykd6.png link to interactive playground - TS 3.5.3 demo running successfully Example with TypeScript 3.7.2 https://i.stack.imgur.com/BPckB.png link to demo - TS 3.7.2 demo not functioning correctl ...

Is it feasible to incorporate a multi-level navigation menu into the "NavItem" component using MaterialUI with TypeScript?

Instructions for creating a multi-level navigation menu using MaterialUI and TypeScript: To the existing '/questions' section, it is desired to include the following 2 navigation menus: /questions/Tags /questions/Users This should resemble the ...

What causes my browser fingerprint to consistently remain unchanged?

declare var Fingerprint2: any; @Component({ selector: 'my-app', template: `Hello`, }) export class App { constructor() { new Fingerprint2().get(function(result, components){ console.log(result); // Device fingerprint as a hash va ...

Create a TypeScript view component that encapsulates an HTMLElement for seamless integration with TweenMax

Looking to develop my own basic view component class that encompasses an HTMLElement or JQuery element, I want to be able to do something similar to this: var newComponent:CustomComponent = new CustomComponent($('#someDiv')); TweenMax.to(newCom ...

Finding the perfect pairing: How to align counters with objects?

public counter = 0; x0: any; x1: any; x2: any; x3: any; x4: any; next(){ this.counter += 1; this.storage.set("Count", this.counter); console.log(this.counter); this.logic(); } logic(){ //automatic counter here var xNum = JSON.parse(JSON.stri ...

Exporting a object in Angular2 Using TypeScript

I've been working on a small Angular2 application using Typescript and things have been going smoothly so far. My goal is to utilize a file called config that contains all the necessary settings for the application. Here's the file in question: ...

Tips for utilizing 'safe-json-stringify' within Angular 4 Application

I have a specific requirement to convert a JSON object to a string. However, simply using JSON.stringify() does not work due to circular references. After some research online, I came across a package that can handle this issue for me. The only problem is ...

Managing Time Before Browser Refresh in AngularLearn how to monitor and examine the time remaining before

In my Angular web application, I am facing an issue where the user's login status is lost every time the browser is refreshed or reloaded. I want to implement a feature that allows the login status to remain active for a short period of time after the ...

Execute environment validation on server during `next build` command

I have a src/config/server/ts file that contains the following code: 'use server'; import zod from 'zod'; if (typeof window !== 'undefined') { throw new Error('env should not be imported on the frontend!'); } co ...

Issue with Nativescript Angular router version 3.0.0-alpha.7 causing navigation errors

This project example highlights a problem: https://github.com/rrcoolp/test-router-app/ Issue with navigation: The test project showcases an issue with NATIVESCRIPT ANGULAR 2 (RC3) and Nativescript router 3.0.0-alpha.7. The problem is straightforward - na ...

Sharing data between two components in an Angular2-Meteor application

I am currently working with angular2-meteor. When attempting to transfer a value between two components (updating the value in the first component triggers an event in the second component where the new value is used), I have two methods available: The ...

A guide on extracting a JSON data with a BigInt type using TypeScript

I am facing an issue with parsing a bigint from a JSON stream. The value I need to parse is 990000000069396215. In my TypeScript code, I have declared this value as id_address: bigint. However, the value gets truncated and returns something like 9900000000 ...

Enhancing performance with React.memo and TypeScript

I am currently developing a react native application. I am using the Item component within a flatlist to display data, however, I encountered an error in the editor regarding the second parameter of React.memo: The error message reads: 'Type 'bo ...

Maintain division contents while navigating

I need a solution to keep my div (NewCall) open even when the user navigates between pages in my Single Page Application. The NewCall div is located in my layout page and is triggered by user click. However, whenever I navigate to another page, the div cl ...

Issue with redirecting users back to the login page after accepting Keycloak required actions due to browser specific terms and conditions

My Keycloak version is 9.0 and my app's front end is built using Angular 8. I have enabled Terms and Conditions while setting the defaults to true. I have customized the t&c page as desired, and it appears when users enter their credentials. Acc ...