Avoid creating a pyramid structure by connecting multiple observables only after ensuring that each one is fully completed

Utilizing rxjs, I am wondering if there is a way to trigger the next function only when the observable has completed. Rather than the nested structure below:

this.Start(data).subscribe(
    (data) => {
        console.log('next');
    },
    (err) => {
        console.log('err');
    },
    () => {
        console.log('complete');

        this.nextFunction()
        .subscribe(
            (data) => {
                console.log('next');
            },
            (err) => {
                console.log('err');
            },
            () => {
                console.log('complete');
                this.nextFunction2()
                .subscribe(
                    (data) => {
                        console.log('next');
                    },
                    (err) => {
                        console.log('err');
                    },
                    () => {
                        console.log('complete');
                        this.nextFunction3()
                        .subscribe(...)
                    }
                );
            }
        );
    }
);

Is there a way to handle it more elegantly like this:

this.Start(data).subscribe(
    (data) => {
        console.log('next');
    },
    (err) => {
        console.log('err');
    },
    () => {
        console.log('complete');
        return other observable;
    }
)
.then(
    (data) => {
        console.log('next');
    },
    (err) => {
        console.log('err');
    },
    () => {
        console.log('complete');
        return other observable;
    }
)
.then(
    (data) => {
        console.log('next');
    },
    (err) => {
        console.log('err');
    },
    () => {
        console.log('complete');
        return other observable;
    }
);

I aim to avoid creating a pyramid-like structure in my code.

Answer №1

To chain observables one after the other, you can utilize the concat operator within RxJS:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/concat';
import 'rxjs/add/observable/defer';

Observable.concat(
  this.Start(data),
  Observable.defer(() => this.nextFunction()),
  Observable.defer(() => this.nextFunction2()),
  Observable.defer(() => this.nextFunction3()),
)
.subscribe();

The defer operator is used to delay obtaining subsequent observables.

If you want to add logging:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/concat';
import 'rxjs/add/observable/defer';
import 'rxjs/add/operator/do';

Observable.concat(
  this.Start(data).do(
    (value) => { console.log("next: Start:", value); },
    (error) => { console.log("error: Start:", error); },
    () => { console.log("completed: Start"); }
  ),
  Observable.defer(() => this.nextFunction().do(
    (value) => { console.log("next: nextFunction:", value); },
    (error) => { console.log("error: nextFunction:", error); },
    () => { console.log("completed: nextFunction"); }
  )),
  Observable.defer(() => this.nextFunction2().do(
    (value) => { console.log("next: nextFunction2:", value); },
    (error) => { console.log("error: nextFunction2:", error); },
    () => { console.log("completed: nextFunction2"); }
  )),
  Observable.defer(() => this.nextFunction3().do(
    (value) => { console.log("next: nextFunction3:", value); },
    (error) => { console.log("error: nextFunction3:", error); },
    () => { console.log("completed: nextFunction3"); }
  )),
)
.subscribe();

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

Guide on dynamically changing the color of polymer 1.0 paper-button from an array of colors

I have an array called buttonColors that contains a set of colors in hex format. I am looking to create paper-buttons, each with the color from the buttonColors array. How can I achieve this in Polymer 1.0? <template is="dom-repeat" items="{{buttonCo ...

Managing key presses with functions in VueJs

Within my component, I am utilizing VueStrap's modal in the following manner: <template> <modal-window v-model="show" v-on:keyup="keyHandler($event)" @ok="submit()" @cancel="cancel()" @closed=" ...

Sending an XMLHttpRequest in PHP causes a blank array to be returned

> xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { var jsondata = xmlhttp.responseText; console.log(xmlhttp.responseText); document.getElementById("jsondata").value = js ...

Cache for JSON Schema in VS Code

After updating to TypeScript 1.5 (now out of beta), I am eager to utilize the json schema helpers in VS Code. Upon configuring tsconfig.json, I noticed that only commonjs and amd module options are available, while umd and system are missing based on this ...

Setting up Redis for session store in the right way involves a few key steps

I have been attempting to configure Redis Store in the following manner: var express = require('express'); var app = express(); ....... ....... var session = require('express-session'); var redis = require("redis").createClient(); var ...

In a Typescript Next Js project, the useReducer Hook cannot be utilized

I'm completely new to Typescript and currently attempting to implement the useReducer hook with Typescript. Below is the code I've written: import { useReducer, useContext, createContext } from "react" import type { ReactNode } from &q ...

Managing incoming HTTP requests on LoopBack can be easily done by following these steps

I am currently working with loopback to create a login page. The client-side files contain the code for the login page $(document).ready(function(){ $('#login').click(function(){ var username = $('#usr').val(); var password = ...

Encountering a Lint error stating "Expected 2 arguments, but received 1" during the testing of the window.scrollBy() function in Jasmine following an Angular

During the upgrade to Angular 11, several other packages, such as jasmine-core, were also upgraded. This caused lint issues when running the 'npm run test' command due to stricter type definitions. One specific issue involves the window.scrollBy ...

Real-time changes may not be instantly reflected in the model update

I need to add two numbers together and display the sum in a third input field: HTML <div ng-app="myApp"> <div ng-controller="MainCtrl as mainCtrl"> Main {{mainCtrl.foo}} <br/> <input type="text" ng-model="mainCtrl.foo"/> ...

The necessity of utilizing a dummy object for storing events in JavaScript is evident in certain situations

I am confused as to why in some instances a dummy object is needed in JavaScript to store events, like in the following code: Metal.Gold = function() { var temp = $("<div>"); //dummy object this.Submit = function(url1, method, data){ ...

Information is being received, but unfortunately, it cannot be displayed

Currently, I am experimenting with using the axios http request to showcase some data. My focus is on exploring how to exhibit api data on the client side with react. If you are interested in seeing my progress so far, feel free to check out the link belo ...

Switching website to mobile version when accessed on a handheld device

Although I'm sure this question has been asked before, I can't seem to find any information on it. I am interested in creating two versions of my website - one specifically for mobile displayed on a subdomain like m., and another version for desk ...

Show the textbox automatically when the checkbox is selected, otherwise keep the textbox hidden

Is it possible to display a textbox in javascript when a checkbox is already checked onLoad? And then hide the textbox if the checkbox is not checked onLoad? ...

Validating data for Telegram Web Bots using JavaScript

Struggling with creating a user verification script for my Telegram web app bots. Need help troubleshooting. import sha256 from 'js-sha256' const telegram = window.Telegram.WebApp const bot_token = '<bot-token>' const data_check_ ...

List component in Angular not refreshing after sorting the array in the service

Currently, I am delving into the realm of Angular (version 5+) to enhance my skills by working on a small project. The project involves setting up basic routing functionalities to showcase the ContactList component upon selecting a navigation tab. Addition ...

Error: An unexpected token < was caught in the TypeScript Express code

Using TypeScript to compile and run an Express server that simply serves an HTML file. However, encountering an error in the response under the network tab in Chrome for app.js: Uncaught SyntaxError: Unexpected token '<' Below is the server c ...

The output is displaying an Object instead of a numerical value in JSON

When I try running the URL in Chrome, the output I receive is: { "Train_score": { "0": 0.9892473118 }, "Test_score": { "0": 0.9831932773 } } However, when I attempt to use the following code to retrieve the JSON data using Javascript, co ...

Implementing data binding with rxjs and Angular 1.6: A step-by-step guide

I've been attempting to fetch data using rxjs from a promise method, and when it is successful, I subscribe to it and pass it to my scope. Although I can see the response object attached to my scope, it doesn't seem to be mapping in the UI. Her ...

Determine the dimensions of a div element in IE after adjusting its height to auto

I am currently working on a JavaScript function that modifies the size of certain content. In order to accomplish this, I need to obtain the height of a specific div element within my content structure. Below is an example of the HTML code I am dealing wit ...

What is the process for executing Express's scaffold by utilizing "nodemon" and the basic "node" command instead of relying on the "npm start" command?

Could you help me locate where I need to make changes in my package.json file? Here is the content of my package.json: { "name": "xyz", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { ...