Home > Back-end >  What is the proper usage of asynchronoscity in an Angular app with injected service?
What is the proper usage of asynchronoscity in an Angular app with injected service?

Time:01-24

My goal is to implement the ability to delete a specific document in a firebase collection, as a button in a component. To do this, I'm using an Angular service to get all the document IDs in a collection, as shown below (because the IDs also have utility in other components):

getCurrUserDocID(){ 
      this.getUsers().subscribe(arr =>{
         this.listUsers = arr.map(item => {
           return{
            userDocID : item.payload.doc.id,
            ...item.payload.doc.data() as User
           }
        })
      }) 

      return{        
        userIDs : this.listUsers
      };

Injecting this service into components does allow me to get the docIDs. However, it's finicky. When I called it in ngOnInit in a component that loads under a navbar tab, it doesn't work unless I click that tab a couple times:

ngOnInit(): void {
    console.log(this.service.getCurrUserDocID().userIDs)
  }

The first and second click return an empty array in the console, while the third finally returns the actual array of data. I suspect this has something to do with observables and asychronous-ity.

CodePudding user response:

You are using a subscription to get the data from this.getUsers() observer. On getting new data you set the value of this.listUsers. Now all you need in your component is to access this.listUsers.

Just remember that every time there will be data coming from this.getUsers() observer the value of this.listUsers will be overwritten which will cause your component to rerender.

The fact you get the data only on the third invocation may be related to the time it takes for this.getUsers() to return date or to the way you use it. You have to notice that the subscription to the observable will return multiple results.

CodePudding user response:

Don't subscribe out of component becouse you will need to unsubscribe it. If you want to sort data use map() operator in pipe().

getCurrUserDocID(){
    this.listUsers = this.getUsers().pipe(
        map(item => {
            return {
                userDocID: item.payload.doc.id,
                ...item.payload.doc.data() as User
            }
        })
    )
};

In component

constructor(public: service: Service) {} // Make it public so you can use it in html file

ngOnInit(): void {
    this.service.getCurrUserDocID() // here just triger `getUsers()` function.
}

In html template with async pipe

<ul>
   <li *ngFor="let item of service.listUsers | async">
      {{item.id}}
   </li>
</ul>

Async pipe in template are subscribing and unsubscribing for you so you no need to worry about data leaks.

  •  Tags:  
  • Related