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

How to utilize FileReader for parsing a JSON document?

I'm currently facing an issue while attempting to read and copy a JSON file uploaded by the user into an array. When using .readAsText(), the returned data includes string formatting elements like \" and \n. Is there a way to utilize FileRe ...

Tips on how to verify if the Angular test with native elements has produced an error

Is there a way to detect errors in an Angular test that uses native elements? The test I am running is as follows: import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { MikeComponent } from './mike.component&a ...

Ways to check my component using ActivatedRoute?

I am currently facing an issue while testing a component that utilizes two resolvers (pagesResolver and UploadResolver): Below is the code snippet for my component: export class AdminPagesComponent implements OnInit { fileUploads$: Observable<FileUpl ...

Encountering a Typings Install Error When Setting Up angular2-localstorage in WebStorm

I am currently using Windows and WebStorm as my development environment. I attempted to install the angular2-localstorage package by running the command npm install angular2-localstorage, but encountered an error. After realizing that the angular2-localst ...

The Aurelia application encounters a "Maximum call stack size exceeded" error while trying to bind FullCalendar

I am currently working on setting up a JQuery plugin (FullCalendar) within my Aurelia application, which is built using TypeScript. I am relatively new to web development and just trying to get a basic example up and running. To start off, I utilized this ...

Having difficulty handling text overflow in Angular4 and HTML

I'm facing an issue with displaying a very large text in a table. Despite trying various attributes such as - { text-overflow: clip; } { text-overflow: ellipsis; } { text-overflow: ellipsis-word; } { text-overflow: "---"; } { text-overflow: ellip ...

Is it possible to create Interactive Tabs using a Global BehaviorSubject?

Trying to adjust tab visibility based on different sections of the Ionic app, an approach involving a global boolean BehaviorSubject is being utilized. The encapsulated code has been condensed for brevity. In the provider/service globals.ts file, the foll ...

Installing a package from GitHub with a specific tag using NPM

Is there a way to install npm into my angular2 project from a git repository using a specific tag like tag = 6.0.0? For example: git <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dabdb3ae9abdb3aeb2afb8f4b9b5b7">[email ...

Unable to retrieve notes(data) from API using the user ID

I am trying to retrieve notes data from an API using user_id, but I am encountering difficulties in making the API call. Despite my attempts to log the error, I am unable to fetch the required data. Can someone assist me in identifying what might be miss ...

What is the best way to execute AJAX requests in a loop synchronously while ensuring that each request is completed

I am looking to implement an AJAX loop where each call must finish before moving on to the next iteration. for (var i = 1; i < songs.length; i++) { getJson('get_song/' + i).done(function(e) { var song = JSON.parse(e); addSongToPlayl ...

Is it possible to implement a redirect in Angular's Resolve Navigation Guard when an error is encountered from a resolved promise?

I have integrated Angularfire into my Angular project and am utilizing the authentication feature. Everything is functioning properly, however, my Resolve Navigation Guard is preventing the activation of the component in case of an error during the resolve ...

Access to this feature is restricted when using a decorator in TypeScript with NodeJS

I have designed a decorator to handle async errors, but I am encountering difficulties in accessing it within class methods. My goal is to develop a reusable CRUD class that other classes can inherit from, with a method for CRUD operations. Decorator Code ...

Issues with Angular unit tests failing due to an unexpected phantomJS error

Executing ng test triggers the execution of my 3 unit tests which have been hardcoded to pass successfully, as shown below: describe('AppComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ ...

Clicking on the button in Angular 2+ component 1 will open and display component 2

I've been developing a Angular 4 application with a unique layout consisting of a left panel and a right panel. In addition to these panels, there are 2 other components within the application. The left panel component is equipped with buttons while ...

Retrieve the observable value and store it in a variable within my Angular 13 component

Incorporating Angular 13, my service contains the following observable: private _user = new BehaviorSubject<ApplicationUser | null>(null); user$ = this._user.asObservable(); The ApplicationUser model is defined as: export interface ...

Attempting to perform an API invocation on a distant endpoint utilizing NestJS

var unirest = require("unirest"); var req = unirest("GET", "https://edamam-edamam-nutrition-analysis.p.rapidapi.com/api/nutrition-data"); req.query({ "ingr": "1 large apple" }); req.headers({ &qu ...

Utilizing the FormsModule and ReactiveFormsModule within a Component module

I am facing an issue with integrating a reactive form into a generated component called boom-covers. I am utilizing the [formGroup] property as shown below: <form name="boomCovers" method="post" id="bomCovers" (ngSubmit)=&q ...

Using the Start-Job command in PowerShell does not seem to be compatible with Selenium

I have a collection of .dll files necessary to run selenium with powershell: The file extensions can be disregarded. Essentially, my goal is to use the Start-Job command to simultaneously open two instances of chrome browsers and navigate to different URL ...

Bringing in AuthError with TypeScript from Firebase

Is it possible to verify if an error is of type "AuthError" in TypeScript when using Firebase? I have a Https Callable function with a try/catch block that looks like this: try { await admin.auth().getUser(data.uid); // will throw error if user doesn& ...

What is the correct way to implement Vue.use() with TypeScript?

I am trying to incorporate the Vuetify plugin into my TypeScript project. The documentation (available at this link) suggests using Vue.use(), but in TypeScript, I encounter the following error: "error TS2345: Argument of type '{}' is not assign ...