Loading data via ajax correct

Hello together,

I have a question regarding the aurelia-fetch-client. Searching in internet, I found a couple of tutorials how to load data for a view-model. Now I want to know your opinion, if there is a recommended way.

Currently my solution looks as follows:

I have a view model:

@autoinject
export class Show {
    @bindable user: User;

    constructor(
        private userService: UserService
    ) {   }

    public attached() {    }

    public  activate( params: any ){
        let id: string = params.id;
        this.user = await this.userService.getUserById( id );
    }
}

and a central user service:

@autoinject()
export class UserService {
    private user: User;

    public getUserById( id: string ): User {
        let user: User = new user();
        this.HttpClient.fetch( "/mytarget-url", { 
headers: this.config.get( 'eventerza-api.api-headers' ), 
method: "GET" } )
            .then( response => { return response.json() } )
            .then( data => { this.user = data; } )
            .catch( err => { throw "Error on requesting User from API, Error: " + err } );
        return this.user;
    }

The disadvantage of this implementation is, that the respective show-view is empty on loading it the first time. Only when I switch to another route and then switch back, the data are loaded and taken over correctly.

Can you give me an example of how to implement the fetch-data the correct way?

Many thanks.

Your service call should only return the promise since HttpClient.fetch().then() will return a promise and happen async and you will just end up with a blank user.

   public getUserById( id: string ): Promise<User> {
        return this.HttpClient.fetch( "/mytarget-url", { 
               headers: this.config.get( 'eventerza-api.api-headers' ), 
               method: "GET" 
            } )
            .then( response => { return response.json() } )
            .catch( err => { throw "Error on requesting User from API, Error: " + err } );
    }

In your activate call change it to:

public  activate( params: any ) {
   let id: string = params.id;
   this.userService.getUserById( id )
      .then(user => { this.user = user; });
}

Optionally you can return that promise in the activate to make the page wait until you have data loaded before rendering.

2 Likes

I found 2 mistakes:

First you are using await to wait for the promise to be resolved, so the activate function has to be marked as async.

Remember, the await keyword is only valid inside async functions. If you use it outside of an async function's body, you will get a SyntaxError.

Second your getUserById method is not returning a promise but a empty user.

you should

return this.HttpClient.fetch( "/mytarget-url", { 
      headers: this.config.get( 'eventerza-api.api-headers' ), 
      method: "GET" 
} )
.then( response => response.json())
.then( data => this.user = data;  )
.catch( err => { throw "Error on requesting User from API, Error: " + err } );
1 Like

@SNO when you flag a function as async, it stops the execution of the code inside that function until you have the promise resolved or rejected. This way you know that the lines of code below, that are dependent on that code will not be executed before you have the data you need. All other code outside this function will continue executing normally.

1 Like