简体   繁体   中英

How to handle async functions in Angular

 //This is a function that is in my data service (in Angular) that basically gets data and puts it in an array getTenantData() { //This is the function that is called by app.component.ts //It's job is to get data from the tenants collection and map it to an array called tenants this.afs //afs is simply what i named the Firebase db in my constructor .collection('tenants') .snapshotChanges() .subscribe(values => { this.tenants = values.map(value => { return { id: value.payload.doc.id, ...value.payload.doc.data() }; }); }); } //Then if I create a function that performs some 'work' on the tenants array in another component like so filterMyArray() { this.ad.tenants.filter(values => { //ad is simply what i called the dataservice in the constructor if (values.id == 'Some Value') { this.filteredArray.push(values); } }); console.log(this.filteredArray); } //This works fine if I call it using some manual 'after load' approach (like clicking a button) //Doesn't work if I call it in ngOnInit for instance as tenants hasn't been populated yet //Throws typeerror cannot read property filter of undefined etc. //So challenge is how do I get the second function to wait for the first //Keep in mind first function is in a service not in the same component as second function 

I keep running up against use cases where I'm needing to deal with asynchronous data while building an Angular application. I've employed a number of strategies to deal with things (async pipe, ngIf waiting for certain variables to be ready etc.) but I feel like I'm missing something. Here are the specifics of the latest challenge... I have an array that is being populated from Firebase. This is being done via a function call upon load of the application. Let's call the array 'sourceArray'

I then want to do some 'work' on that array to seed content elements in other components. For example doing a 'filter' on that array and creating a new array from those results.

The challenge I keep running into (this is just the latest example) is that when I call the function that does 'other work' on the sourceArray I get errors back saying blah blah is undefined because it hasn't been fully populated from firebase yet. So to break this down simply... -Source variable being populated from something that takes some 'time' -Want to do work on that source variable only 'after' it's been fully populated

I've read up on using lifecycle hooks (Ie putting the dependent function in a hook that runs after the source function) etc. and have limited success using that strategy. Also of note I'm 'subscribing' to the firebase data in the source array.

I've also investigated potentially using async and await but don't really understand how I would apply that to this use case. Any advice would be appreciated and happy to provide more details if this is not sufficient.

// This is how you can await a call from firebase 
// & later do something after call is completed

// write
async function writeData (userId, name, email, imageUrl) {
 await firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
  // do something when after is executed
}

// read
async function readData (userId) {
 let response = await firebase.database().ref('/users/' + userId).once('value')
 console.log(response.val())
 // do something after above is executed 
}

First, you are not using the filter() method as intended. You are using it like how you'd use map() . You could just do

filterMyArray() {
 this.filteredArray = this.ad.tenants.filter(values => values.id == 'Some Value');
  console.log(this.filteredArray);
}

For your main concern, you could setup a watcher in your service that filters out the original array when it's populated.

constructor() {
  this.setupWatcher();
}

setupWatcher() {
  interval(1000).pipe(
        switchMap(() => of(this.ad.tenants)),
        filter(response => response && response.length > 0),
        take(1))
        .subscribe((input: Tenants[]) => {
          //do stuff
          this.filterMyArray(input);
        });
}

And then,

filterMyArray(originalArray: Tenants[]) {
  this.filteredArray = originalArray.filter(values => values.id == 'Some Value');
  console.log(this.filteredArray);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM