Issue with subscribing to nested observables, unable to successfully unsubscribe

My app is using Firebase auth with Firestore (https://github.com/angular/angularfire2). Despite my efforts to unsubscribe from all observables fetched from Firestore before signing out, I keep encountering a "FirebaseError: Missing or insufficient permissions" issue. This error seems to stem from a nested subscription within another subscription in the code snippet below.

Even after unsubscribing from both subscriptions in the ngOnDestroy method, the error persists.

this.proposalSubscription = this._posts.retrieveProposals(user.uid)
  .subscribe(proposals => {
      this.proposals = proposals;
      this.proposals.forEach(proposal => {
        this.chatSubscription = this._chat.retrieveChat(proposal.id).subscribe(chat => {
          if (chat) {
            this.chats.set(proposal.id, chat)
          }
        });
      })
    });

I suspect that the problem lies in this line of code:

this.chatSubscription = this._chat.retrieveChat(proposal.id).subscribe(chat => ...
Even though I ensure to unsubscribe from both proposalSubscription and chatSubscription before signing out, the error persists. Can anyone suggest a solution to this issue? Additionally, I have limited experience with rxjs and its operators. Is there an operator that can help avoid such nested subscriptions?

Any insights would be greatly appreciated. Thank you.

Answer №1

To establish your subscription, follow these steps:

this.subscriptionModel = this._posts.requestSubscriptions(user.uid)
                                    .pipe(
                                      switchMap(subscriptions => {

                                        // Save subscriptions in a class variable like this
                                        this.subscriptions = subscriptions;

                                        const obs$ = subscriptions.map(s => {
                                          return this._chat.getChat(s.id)
                                                     .pipe(
                                                       map(chat => {
                                                         this.conversations.set(s.id, chat);
                                                       })
                                                     )
                                        });

                                        return forkJoin(obs$);
                                      })
                                    )
                                    .subscribe();

You have the flexibility to arrange your operator chain as desired and maintain only one subscription.

In ngOnDestory, remember to unsubscribe from the subscription:

ngOnDestroy() {

 if(this.subscriptionModel) {
   this.subscriptionModel.unsubscribe()
 }
}

If you anticipate evaluating the

this._posts.requestSubscriptions(user.uid)
observable only once, you can eliminate the explicit unsubscribe in ngOnDestroy by using take(1) like this:

this._posts.requestSubscriptions(user.uid)
                                    .pipe(
                                      take(1),
                                      switchMap(subscriptions => {

                                        // Save subscriptions in a class variable like this
                                        this.subscriptions = subscriptions;

                                        const obs$ = subscriptions.map(s => {
                                          return this._chat.getChat(s.id)
                                                     .pipe(
                                                       map(chat => {
                                                         this.conversations.set(s.id, chat);
                                                       })
                                                     )
                                        });

                                        return forkJoin(obs$);
                                      }),                                          
                                    )
                                    .subscribe();

Answer №2

When it comes to managing dependent observables, using switchMap instead of nested subscriptions is a more efficient approach. To handle multiple subscriptions within the same component, employing takeUntil allows you to emit a single value into a subject and cancel all subscriptions simultaneously. By mapping proposals to an array of observables and utilizing combineLatest, you can obtain an array containing the results of those observables.

finalise = new Subject();

this._posts.retrieveProposals(user.uid)
  .pipe(
    switchMap(proposals => combineLatest(proposals.map(proposal => this._chat.retrieveChat(proposal.id)))),
    takeUntil(finalise)
  ).subscribe(chats => {
    const chat = proposals.find(p => p);
    this.chats.set(proposal.id, chat)
  });

In the ngOnDestroy method:

this.finalise.next();

This will effectively terminate all subscriptions linked to finalise in the takeUntil operator.

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

Fixing the issue "Unable to access property 'toDataURL' of undefined" in the Angular2 signaturePad

I am currently developing a project using Angular 7 and I am facing an issue with implementing signature functionality. I decided to use the "angular2-signaturepad" package for this purpose, and everything is working smoothly until the user completes drawi ...

Integrate a service component into another service component by utilizing module exports

After diving into the nestjs docs and exploring hierarchical injection, I found myself struggling to properly implement it within my project. Currently, I have two crucial modules at play. AuthModule is responsible for importing the UserModule, which conta ...

Tips for accessing child elements within an Angular component

I'm struggling to get a reference of child elements within a component. I have experimented with ElementRef, TemplateRef, QueryList, ViewChild, ViewChildren, ContentChild, and ContentChildren without success. <app-modal> <section #referenc ...

I am having trouble with the TypeScript compiler options not being detected in Visual Studio 2015

After creating an ASP.NET 5 Empty Website project in Visual Studio 2015, I set up a tsconfig.json file with the following settings: { "compilerOptions": { "noImplicitAny": false, "noEmitOnError": true, "removeComments": false ...

Creating a new line in the content of a MatDialog in Angular 7

I have a situation where I am using MatDialog and attempting to insert a new line in the content definition. I've tried using both \n and </b>, but neither of them seem to work. Is there an alternative way to achieve this without manually e ...

React approach for managing multiple combobox values

Currently, I'm working on a page where users can upload multiple files and then select the file type for each file from a dropdown menu before submitting. These 'reports' are the uploaded files that are displayed in rows, allowing users to c ...

The use of the `/deep/` combinator in CSS has been phased out and is set to be completely removed

After updating my angular to version 4.0.0 and chrome to 62.0.3202.94, I encountered the following error message: [Deprecation] /deep/ combinator in CSS is deprecated and will be removed in M63, around December 2017. Refer to for more information. The ...

Issue with ngbCollapse feature when attempting to collapse multiple dynamically generated divs on a single page

When dynamically generating ngbCollapse in a main loop that checks for the presence of the Sun in a JSON object, if the Sun is not there, it provides an option to Add_Sun(). Since it is within a loop, it allows adding a sun to every row. When clicking th ...

Finding the file path to a module in a NextJS application has proven to be a challenge when utilizing the module

Currently, I am utilizing the webpack plugin module-federation/nextjs-mf, which enables us to work with a micro-frontend architecture. Based on the official documentation and referencing this particular example, it is possible to share components between ...

Error encountered in Typescript while attempting to $set a subdocument key value in MongoDB

This is a sample data entry. { _id: ObjectId('63e501cc2054071132171098'), name: 'Ricky', discriminator: 7706, registerTime: ISODate('2023-02-09T14:23:08.159Z'), friends: { '63e502f4e196ec7c04c4 ...

Utilize Angular2 services to showcase a JSON object on the front end

Seeking assistance with displaying a JSON file containing multiple arrays on the front-end using Angular2 Services in Typescript. Can anyone provide guidance? If someone could assist in improving this code by incorporating Model and Interface classes, it ...

Using browser.actions().mouseMove() in conjunction with sendKeys results in a syntax error

I am currently working on a test automation project and utilizing protractor with the jasmine framework. I am facing an issue while dealing with an autocomplete selection drop-down (for example, a countries' name drop-down). I want to input keys into ...

Tips for obtaining the iframe #document with cheeriojs?

I've been struggling to scrape the anime videos page [jkanime], specifically with extracting the mp4 video formats embedded in an iframe #document. Despite trying to use cheerio for querying, I've only managed to retrieve src links from Facebook ...

Conceal the Header on the Login Module

Within my app.component, I have a header and body component. <app-header></app-header> <div class="body"> <router-outlet></router-outlet> </div> I am looking to hide the header element when in the login co ...

Navigate directly to the dashboard page in Angular 5 using RxJS without needing to load the main page first

Utilizing Firebase as the API in my application for authentication, database management, and storage. Implemented a main page (localhost:4200) that loads when the user is not logged in, and a dashboard (localhost:4200/dashboard) for authenticated users. ...

ABP's Angular DateTimePicker Component for Effortless Date and Time

I am experiencing an issue with a DateTime field that is supposed to display only the time: HTML: <div class='input-group date'> <input class="form-control" type="datetime" #RequiredByDate name="RequiredByDate" [value]="formatDate(h ...

What is the best way to delete an item from a React array state?

In my Firebase database, I have an array stored under the root branch called Rooms. Within the app, there is a state named rooms which is also an array. I successfully set it up so that when a user enters a new room name and submits it, it gets added to th ...

Angular universal issue: 404 error code failing to function properly

After numerous attempts, I find myself at a dead end. Our Angular 11 website requires Universal for SEO purposes, and we have set up a 404 page to redirect when necessary. The issue arises when the redirect returns a status code of 200 instead of 404. To ...

Leveraging pipes in Angular 2 within the (click) event handler

I have a question that may seem simple, but I'm struggling to figure out how to use a pipe within an event like (click). Here is an example of what I'm trying to do: <button (click)="quizAnswers(answer?.texte | translate | async)"></but ...

The Angular subscribe value is consistently assigned as -1, just before it receives the actual assigned value

Upon completion of the .subscribe, I am attempting to trigger an event as the subsequent code relies on the result. checkIfBordereauExists(id: string) { return this._BourdereauService.get_one(id).subscribe( data = > { if (data.i ...