Tips for emitting only the last request in a subscribe function

When I use the complex logic inside the concatMap operator to send a form, everything works fine. However, in my subscribe method, I am encountering an issue where additional http requests are being fired twice instead of once. I attempted to resolve this by using the takeLast operator, but it did not solve the problem. My goal is to ensure that the requests in the subscribe method are only made after all requests have been completed within the concatMap.

makeRequest(value) {
  const team = toFormData(this.form.controls.profile.value);

  this.teamService
  .sendTeam(team)
  .pipe(
    concatMap(() => {
      const tasks$ = [];

      for (const [index, m] of this.form.controls.members.value.entries()) {
        const member = toFormData(m);

        if (m.id) {
          tasks$.push(this.teamService.updateMember(member, m.id).pipe(take(1)));
        } else if (!member.entries().next().done) {
          if (member.has('name')) {
            tasks$.push(this.teamService.createMember(member).pipe(take(1)));
          } else {
            (this.form.controls.members as FormArray).controls[index].markAllAsTouched();
            this.scrollToFirstInvalidControl();
          }
        }
      }

      return tasks$.length ? concat(...tasks$) : EMPTY;
    }),
  )
  .subscribe(() => {

    this.teamService.getMembers().subscribe();

  });
}

What should be done to ensure that only necessary requests are made?

Answer №1

Utilizing takeLast was a smart move, but the key lies in where it's positioned:

this.teamService
  .sendTeam(tem)
  .pipe(
    concatMap(() => {
      /* ... */

      return tasks.length ? concat(...tasks).pipe(last()) : EMPTY;
    }),

    // You can avoid manually subscribing in the `subscribe` callback
    switchMap(() => this.teamService.getMembers())
  ).subscribe()

concatMap subscribes to an observable created by the provided callback function.

In this particular scenario, that observable could be either concat(...tasks).pipe(last()) or EMPTY.

If it's concat(...tasks).pipe(last()), it will wait for each task to finish. The use of last also incorporates takeLast(1) internally.

By the way, concat can be visualized as follows:

// concat(observables[])

from(observables[])
  .pipe(
    mergeMap(obs$ => obs$, 1)
  )

If it's EMPTY, a complete notification will immediately be sent, indicating that teamService.getMembers() from

switchMap(() => this.teamService.getMembers())
won't be triggered.

Answer №2

In order to receive a response and process your data, you are not utilizing any value from the sendTeam method.

executeRequest(data) {
  const teamData = processDataForForm(this.form.controls.data.value);
  new Observable(observer => {
    this.teamService
    .sendRequest(teamData)
    .subscribe(() => {
      const tasks$ = [];
        for (const [index, item] of this.form.controls.elements.value.entries()) {
          const elementData = processData(item);

          if (item.id) {
            tasks$.push(this.teamService.updateElement(elementData, item.id).pipe(take(1)));
          } else if (!elementData.entries().next().done) {
            if (elementData.has('name')) {
              tasks$.push(this.teamService.createElement(elementData).pipe(take(1)));
            } else {
              (this.form.controls.elements as FormArray).controls[index].markAllAsTouched();
              this.scrollToFirstInvalidControl();
            }
          }
        }

        observer.next(tasks$.length ? concat(...tasks$) : EMPTY);
    });
  }).subscribe(() => {

    this.teamService.getElements().subscribe();

  });
}

Answer №3

It seems like the perfect data structure for your needs is the ReplySubject. This specialized subject will serve as a container for the most recent emitted value.

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

Error message: "ExpressionChangedAfterItHasBeenCheckedError - encountered while using ngIf directive to hide/show a progress

My HTTP interceptor is set up to display a loading bar whenever an HTTP request is made: intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const dataStorageService = this.injector.get(DataStorageService); ...

Creating a JSON object from two arrays is a simple process

Consider the following two arrays: let values = ["52", "71", "3", "45", "20", "12", "634", "21"]; let names = ["apple", "orange", "strawberry", &q ...

Access uninitialized properties in Typescript post-compilation

I am currently in the process of creating a wrapper for socket.io. Coming from a strong object-oriented background, I aim to incorporate the idea of Models into my framework/wrapper. For those familiar with socket.io, you may know that data associated wit ...

Register the route data in Angular 2 dynamically

I am facing a challenge where the routing data is stored in the Database. To create routing dynamically at run time, I need to retrieve the value from the Database. Unfortunately, I have not come across any options to load route data before route initializ ...

Steps to show the chosen index value in an alert pop-up using Ionic 2 framework

I'm in the process of trying to showcase a selected index value within an Ionic 2 alert box. However, I'm struggling to find the correct method to display it in the Ionic prompt. This pertains to the home.ts import { Component } from '@ang ...

How to dynamically update Angular6 query parameters without changing routes

Lately, the project I've been focused on involves managing numerous lists with search, sort, and pagination functionalities. I have successfully implemented data fetching from an API based on these criteria. Recently, a new requirement emerged - the ...

Puzzled by the specialized link feature

As I delve into the world of React and Next.js, I find myself working on the link component. Initially, I had a grasp on basic routing in next.js which seemed pretty straightforward. However, things took a confusing turn when I stumbled upon this code: imp ...

Variable type linked to interface content type

Is it possible to link two fields of an interface together? I have the following interface: export interface IContractKpi { type: 'shipmentVolumes' | 'transitTime' | 'invoices'; visible: boolean; content: IKpiContent; } ...

The React context hooks are failing to update all references

In my project, I am working on setting up a modal with a custom close callback. To achieve this, I used a useState hook to store the method and execute it within an already defined function called closeModal(). However, I encountered an issue when attempt ...

A guide on updating a MySQL table using a JSON object in Node.js

I have a JSON Object and need to UPDATE a mySQL table without listing all of the keys individually For an INSERT operation, I use the following code: var arrayValue = Object.keys(obj).map(function(key) { return String("'"+obj[key]+"'"); ...

Retrieve the validation result using `Express-validator .getValidationResult()` function

Struggling with implementing proper validation for a basic web application login system. Despite extensive research on express-validator and scouring resources like npm documentation, tutorials, and Stack Overflow, I am unable to resolve the issue related ...

I keep encountering a syntax error every time I attempt to run the yarn start command

Upon attempting to execute yarn start, an error appeared in the command line indicating a syntax error. I have already attempted updates on both node and yarn. $ node --max_old_space_size=8192 ./node_modules/.bin/ng serve -H 0.0.0.0 --disable-host-check ...

Angular form group not providing data upon submission

Encountering a peculiar issue here. When the submit button is clicked, my angular form group does not return anything. Additionally, nothing is being logged to the console upon clicking. Interestingly, this form is almost identical to another one that func ...

Removing data based on various criteria in Prisma

While I understand that the where clause in Prisma requires a unique input for its delete operation, I have utilized the @@unique function to ensure that multiple conditions need to be columns together and must be unique. However, I am struggling with how ...

What do those numbers signify once the Angular app is developed?

After completing the production build of my Angular app, I noticed a series of numbers added to the reference of external files. Can anyone explain what this signifies? <script src="js/shims.js?1501242878494"></script> <script src="js/app ...

React and TypeScript - `Component<Props & {}>`

Can you explain the meaning of this code snippet? export class App extends Component<Props & { some: string; some2: string; }> Specifically, what does the & sign indicate in this context? & { some: string; some2: string; } ...

Inquiry from a novice Angular user

Hello fellow members of the Angular community, I am embarking on an Angular project for my school and it's my first time delving into this framework. I could really use some guidance to get started smoothly. Initially, I set up a new project, instal ...

Dynamically generating PWA manifests in Angular 7

I just finished building a Progressive Web App (PWA) using Angular 6. Now, I am looking to customize the icons and start URLs dynamically because the app will be accessed through different URLs, each with its own unique logo assigned to it. Is there a way ...

Troubleshooting issue with the functionality of nodejs async await flow

My goal is to implement an endpoint that allows users to download a video and then upload it to YouTube. Here is the process I follow: First, I extract the video URL from the request body. Next, I save the video to a temporary folder. After that, I procee ...

Can you divide and repurpose several function overloads in TypeScript?

I've put together this sandbox of code In my project, there are 2 functions named slice in separate classes. They both contain a lengthy and repetitive set of overrides: export class Atom<S> { constructor(private initial: S) { } // Se ...