The art of linking Observables on the fly in rxjs and angular

In my current project, I am facing a challenge where multiple events can be triggered from an object. These events are handled by a component and then sent to a REST API. The issue arises when I need to ensure that calls to the REST API for a specific resource are made in sequence. For example, I have the following methods:

someObjectCreated(objectCreated){
    this.http.post(...);
}

someObjectNameChanged(objectNameChanged){
    this.http.post(...);
}

someObjectDeleted(objectDeleted){
    this.http.delete(...);
}

These event handler methods can be executed at any time. Consider a scenario where someObjectCreated is called, followed immediately by someObjectNameChanged before the POST of someObjectCreated has even completed.

I am wondering if there is a way to chain the outcomes of these observables. Would it be more efficient to convert them to promises and chain them using .then()? Are there any common design patterns in Angular that can help solve this problem?

Answer №1

If you want to implement a chain of operations using the Observable.flatMap operator, follow this example:

this.service.someObjectCreated(object)
    .flatMap(objectChanged => this.service.updateObjectName(objectChanged))
    .flatMap(result => this.service.deleteObject(result))
    .subscribe(finalResult => {
          console.log(finalResult);
     });

Answer №2

In my opinion, it is important to add a loader before sending any request and remove it after completion. Additionally, make sure to update your object based on the response received. If you send a second request with the same object before receiving the first response, you risk losing the original data.

Answer №3

It seems like the solution does not rely on RxJS, you are correct. Instead of using RxJS, you can link necessary actions with promises. One approach could be to create a versatile function or class for this purpose (without error handling, just offering an example):

class ActionQueue {

    private currentTask: Promise<void> = Promise.resolve();

    public execute(action: () => Promise<void>): Promise<void> {
       const prevPromise = this.currentTask;
       // Replace current promise with next task
       this.currentTask = new Promise<void>(async (resolve, reject) => {
            // Wait for previous tasks to complete
            await prevPromise;
            // Execute the submitted action
            await action();
            // Resolve current promise to proceed onto the next action
            resolve();
        });
        return this.currentTask;
    }

}

This way, you can connect any promise-returning function if needed:

objectCreatedEvent(objectCreated){
    this.actionQueue.execute(() => this.http.post(...));
}

objectNameChangedEvent(objectNameChanged){
    this.actionQueue.execute(() => this.http.post(...));
}

Answer №4

Consider using the chain method flatMap() in this manner

this.service.someObjectCreated(queryParam)
    .flatMap((someObjCreatedRsp) => {
        console.log('someObjCreatedRsp', someObjCreatedRsp);
        return this.service.someObjectNameChanged(queryParam)
    })
    .flatMap((someObjNameChangedRsp) => {
        console.log('someObjNameChangedRsp', someObjNameChangedRsp);
        return this.service.someObjectDeleted(queryParam)
    })
    .subscribe((someObjDeletedRsp) => {
        console.log('someObjDeletedRsp', someObjDeletedRsp);
    });

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

What is the best way to determine if the current page in Ionic 2 is being loaded from the sidemenu?

In my Ionic 2 application, there is a page that can be accessed either by clicking on a link in the sidenav or being active by default when the app is loaded. However, I want to implement an additional feature only when the page is accessed through the sid ...

Refine current attributes of an object in Typescript

In typescript, I have an object of type any that needs to be reshaped to align with a specific interface. I am looking for a solution to create a new object that removes any properties not defined in the interface and adds any missing properties. An exam ...

Creating uniform-sized cards with CSS and Bootstrap

Is there a way to ensure consistent card size across all lines? I've noticed that the cards in the second line are taller. Can we base the height of all cards on this? https://i.sstatic.net/KgZwu.png Below is the HTML code: <div class="row"&g ...

Encountering an "Invalid parameter: redirect_uri" error in Keycloak while manually refreshing the page

This is an Angular 17 single-page application utilizing the latest version of keycloak-angular (15.2.1 at the time of writing). I'm facing a perplexing issue where after successfully authenticating and logging out, if I reload the page, it breaks enti ...

What is the reason behind the warning about DOM element appearing when custom props are passed to a styled element in MUI?

Working on a project using mui v5 in React with Typescript. I am currently trying to style a div element but keep encountering this error message in the console: "Warning: React does not recognize the openFilterDrawer prop on a DOM element. If you in ...

Is it possible to utilize a variable within the 'has-text()' function during playwright testing?

With Playwright, I am attempting to locate an element based on the value of a variable For instance: let username = 'Sully' await page.click(`li:has-text(${username})`) However, I encounter the following error: page.click: Error: "has-tex ...

Troubleshooting: Why is Angular2 ngClass malfunctioning?

I am having trouble adding a class based on a condition <tr *ngFor="let time of times; let i = index"> <td [ngClass]="{'red-time':checkInvalid(time['Proles Arrive'])}">{{time['Proles Arrive']}}</td& ...

Managing a project with multiple tsconfig.json files: Best practices and strategies

I've got a project structured in the following way: \ |- built |- src |- perf |- tsconfig.json |- typings |- tsconfig.json My main tsconfig.json looks like this: "target": "es6", "outDir": "built", "rootDir": "./src", Now, I need to have a ...

What is the best way to assign the value of "this" to a variable within a component using Angular 2 and TypeScript?

In my component, I have the following setup: constructor() { this.something = "Hello"; } document.addEventListener('click', doSomething()); function doSomething(e) { console.log(this.something) // this is undefined } I am struggling to a ...

Netlify failing to build CRA due to inability to locate local module for method?

I encountered an issue with deploying my site on Netlify. The problem arises when it fails to locate local modules. Below is the log: 12:54:43 AM: Build ready to start 12:54:45 AM: build-image version: 09c2cdcdf242cf2f57c9ee0fcad9d298fad9ad41 12:54:45 AM: ...

Guide on Reacting to an Occurrence in Angular

I have a scenario where an event is triggered every 10 seconds. After subscribing to the event on the receiving end, I need to figure out how to send data back to the class responsible for emitting the event. constructor(@Inject(ABC.XYZ) private events: ...

The RemoveEventListener function seems to be malfunctioning within Angular2 when implemented with TypeScript

I am currently incorporating three.js into Angular2. The code I am using is quite straightforward, as shown below. this.webGLRenderer.domElement.addEventListener('mousedown', ()=>this.onMouseDown(<MouseEvent>event), false); this.webGLR ...

Searching for the correct navigation menu path using Angular 5's query functionality

Struggling to retrieve the Angular path query from the navigation menu. Every attempt I make with the code below results in undefined or null: this.route.paramMap.subscribe(params => this.Name = params.get('name') ); Here ...

What is the best data type in Asp Net Core C# for capturing Angular's blob object?

I am working with an image BLOB object in Angular 5 and need to send it to the backend via an API. In previous versions of Asp.Net, there was 'HttpBaseType' for this purpose, but it is not available in Asp.Net core. Which data type should be use ...

Adding Images Using Angular 8

I'm encountering difficulties with image upload in the file located at '../src/app/assets/'. Below is the Form I am using: <form [formGroup]="formRegister" novalidate=""> <div class="form-group"> <label for="ex ...

Utilizing useLocation for Defining Text Styles

I'm currently integrating TypeScript into my project, but I'm encountering an error related to 'useLocation' in my IDE. Any thoughts on what might be causing this issue? import React from "react"; import { useHistory, useLocat ...

Validating forms using TypeScript in a Vue.js application with the Vuetify

Currently, I am attempting to utilize Vue.js in conjunction with TypeScript. My goal is to create a basic form with some validation but I keep encountering errors within Visual Studio Code. The initial errors stem from my validate function: validate(): v ...

Using setAttribute will convert the attribute name to lowercase

When creating elements, I use the following code: var l = document.createElement("label");. I then assign attributes with l.setAttribute("formControlName","e");. However, a problem arises where the setAttribute method converts formControlName to lowercase ...

Finding the right way to cancel a Firestore stream within a Vue component using the onInvalidate callback

Currently, I am utilizing Vue 3 to develop a Firebase composable that is responsible for subscribing to an onSnapshot() stream. I have been attempting to unsubscribe from this stream by invoking the returned unsubscribe() function within both watchEffect ...

Karma Error: Unexpected token import in Angular 2 - Uncovering a Syntax Error

I've been exploring this insightful tutorial on https://www.youtube.com/watch?v=yG4FH60fhUE and also referencing https://angular.io/docs/ts/latest/guide/testing.html to create basic unit tests in Angular 2 and ensure the proper setup of Karma. I encou ...