2

I'm having an issue where I am using an async function in Angular 6 data binding:

<span *ngIf="application.status == 'in-progress'; else new">
  {{getAssignedUser(application.user_id)}}
</span>

The getAssignedUser() is an async function which fetches a document from Firestore and I want to display the assigned user's firstname which I received from Firestore. The only problem here is I can't display the firstname value OnInit. If I insert a button and add a click event, it displays the name.

Component:

async getAssignedUser(id): Promise<string> {
    if (id != null) {
        return this._usersService
        .getUserById(id)
        .then(data => {
            this.assignedUser = data.user_fname;
            return this.assignedUser;
        })
    } else {
        return null;
    }
}

Service:

getUserById(id): any {
    let user: any;
    user = this.afs.collection('agents').doc(id).ref.get().then(function (doc) {
        if (doc.exists) {
            user = doc.data();
            console.log(user);
            return user;
        }
        else {
            console.log('No such document');
        }
    }).catch(function (error) {
        console.log('Error getting document: ', error);
    })
    return user;
}

Any help please?

7
  • 2
    Can you provide us with a stackblitz fro your example to be more clear ? Commented Nov 10, 2018 at 23:48
  • What is it you're trying to display? You're doing {{getAssignedUser(application.user_id)}}, but getAssignedUser returns a Promise. You could use an async pipe, like {{getAssignedUser(application.user_id) | async }} Commented Nov 10, 2018 at 23:49
  • @user184994 I'm trying to display a string actually. I don't know how to get the string value from the Promise. It's working with a click event. To be even more precise, I'm actually using an id to retrieve data from another Firestore document and want to access that document values. Commented Nov 10, 2018 at 23:53
  • You can try using the async pipe to get the value out, which would be {{getAssignedUser(application.user_id) | async }} Commented Nov 10, 2018 at 23:55
  • 1
    That;s one of the downsides of calling functions from within the template: the function is called for every change detection cycle. Instead, why not called getUserById in ngOnInit, and just use {{assignedUser}} in your template? Commented Nov 11, 2018 at 0:01

2 Answers 2

0

Issue

The issue with making the call getAssignedUser from the html and expecting to return the value. This will not guarantee because getAssignedUser performs async operation. You had mentioned the async operation on getAssignedUser however does not returns any Observable or Promise.

Solution

You need to change in both services and component. Function should return the Promise to handle this case.

Service:

  getUserById(id): any {

    return new Promise((resolve, reject) => {

      this.afs.collection('agents').doc(id).ref.get().then(function (doc) {
        if (doc.exists) {
          user = doc.data();
          console.log(user);
          resolve(user);
        }
        else {
          resolve(null); //<-- you can reject if you want.
        }
      }
    }
  }

Component:

async getAssignedUser(id): Promise<string> {
        return this._usersService
        .getUserById(id);
}

html

<span *ngIf="application.status == 'in-progress'; else new">
  {{getAssignedUser(application.user_id)} | async}
</span>

Important : You should not function in html, it may lead to multiple call and will impact on the performance. Better would be to use function instead.

Note : code is written directly to stackoverflow editor so there could be typo or syntactical error. So please correct yourself.

Sign up to request clarification or add additional context in comments.

2 Comments

async is required only to observable, not for promises.
@sleepz - please create stackblitz demo to get it fix quicker and easier way.
0

Agree with @Sunil Singh Above Answer, small correction in template file. async operator is mainly used for observable. You can call without that it should work.

<span *ngIf="application.status == 'in-progress'; else new">
  {{getAssignedUser(application.user_id)}}
</span>

1 Comment

Not true, the async pipe also works with promises. Please check the description in the docs

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.