Progressive series of observable conditions

The issue at hand:

I am faced with the task of checking multiple conditions, some of which lead to the same outcome.

Here is the current flow:

  1. First, I check if a form is saved locally
  2. If it is saved locally, I display text 1 to the user
  3. If not saved locally, I then check if the server has this form in its database
  4. If the server does have the form, I show text 2
  5. If the server does not have the form, I show text 1

Is there a more efficient way to handle these conditions that ultimately lead to the same result?

Currently, the logic looks like this:

iif(
  () => this.savedLocally,
  this.showText1(),
  this.checkOnServer().pipe(
    switchMap(onServer => iif(
      () => onServer,
      this.showText2(),
      this.showText1()
    ))
  )
)

If another condition is added, it adds another level repeating this.showText1() somewhere.

I am seeking a redesign of this logic to minimize repetition.

The challenge lies in the fact that all three checks need to be performed in a specific order, and they are all asynchronous.

If it were a simple if, I could use

if (cond1 && cond2 && cond3)
, but the situation here is more complex. The checks must be sequential and each one depends on the result of the previous check.

Answer №1

Is it necessary to use observables in this scenario? It seems like you could achieve the same outcome using a simpler async function

async () => {
    if(this.savedLocally) return this.showText1();

    const isOnServer = await this.checkOnServer();
    if(isOnserver) return this.showText2();

    const isAnotherCondition = await this.checkAnotherCondition();
    if(isAnotherCondition ) return this.showText3();

    return this.showText1();
}

Answer №2

Describing a scenario where each observable in a collection determines the utilization of the next observable.

If an observable's value does not meet a condition, the subsequent observable's value is used until the end of the collection. However, if an observable satisfies a condition, no further observables are needed.

Upon completion of the observable, accumulation of conditions is required.

The goal is scalability, enabling resolution of a series of conditions asynchronously while halting unnecessary logic.

This can be achieved by using a combination of a high-order observable, reducers, and a state object.

A high-order observable emits another observable, creating a nesting effect.

const higherOrder$ = of(of(true));

A state object holds the satisfy condition and accumulated values.

interface State {
   satisfy: boolean;
   values: {[key:string]: any};
}

A default state value is initialized.

const DEFAULT_STATE = {
   satisfy: false,
   values: {
      savedLocally: false,
      onServer: false
   }
};

Observables emitting values to be accumulated are defined.

  • Each observable emits satisfy and values.
  • As long as satisfy is false, the next observable is selected.
  • Values are accumulated in the final result.
const savedLocally$ = this.http.get(...).pipe(map(resp => ({
    satisfy: Boolean(resp), values: {savedLocally: resp}
})));

const checkOnServer$ = this.http.get(...).pipe(map(resp => ({
    satisfy: Boolean(resp), values: {onServer: resp}
})));

A high-order observable switches between observables, accumulates results, and stops at the first satisfied value.

The scan() operator is utilized to accumulate values for each emitted value.

of(savedLocally$, checkOnServer$).pipe(
   switchMap(ob$ => ob$),
   scan((acc, next) => ({
      satisfy: next.satisfy,
      values: {...acc.values, ...next.values}
   }), DEFAULT_STATE),
   filter(state => state.satisfy),
   first(),
   map(state => state.values)
).subscribe(values => console.log(values));

While this approach may not necessarily be simpler than your current method, it allows for scaling to handle a large collection of observables.

In this example, the switchMap() function does not access previous state values. Achieving this would involve a more complex process that requires additional consideration.

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

Is it possible to modify the host header within an Angular app?

I'm experiencing a vulnerability issue and to resolve it, I need to utilize SERVER_NAME instead of the Host header. Is it possible to accomplish this using Angular? ...

Utilizing FullCalendar to fetch information via HTTP

Looking to incorporate FullCalendar with the capability to fetch data via HTTP and open a dialog box when a date is selected. Is there a recommended library for this specific setup? Alternatively, does anyone have a pre-existing example I could reference ...

typescript tips for incorporating nested types in inheritance

I currently have a specific data structure. type Deposit { num1: number; num2: number; } type Nice { num: number; deposit: Deposit; } As of now, I am using the Nice type, but I wish to enhance it by adding more fields to its deposit. Ultima ...

Tips for displaying or concealing a div using Angular Js

I have set up two div elements with a dropdown control in one named div1. I am looking to hide div2 until a value is selected in the dropdown. How can I show or hide a div based on ng-change, ensuring that div2 remains hidden until a value is selected? Cod ...

Tips for importing a PDF file and storing it in your database

I have a project using Angular 7, .NET Framework, and MongoDB where I am creating user profiles. One of the requirements is to allow users to optionally upload a PDF file along with their other information. This is what I have implemented so far: <labe ...

What is the procedure for renaming an item within a basic array in Angular?

I am working on a project in Angular and have constructed an array. I am now looking to change the name of one of the items in this array. While I have figured out how to rename keys in an array, I'm still unsure about how to do so for its values. ...

Can classes be encapsulated within a NgModule in Angular 2/4?

Looking to organize my classes by creating a module where I can easily import them like a separate package. Take a look at this example: human.ts (my class file) export class Human { private numOfLegs: Number; constructor() { this.numOfLegs = 2 ...

Using Typescript to remove an element from an array inside another array

I've encountered an issue while trying to remove a specific item from a nested array of items within another array. Below is the code snippet: removeFromOldFeatureGroup() { for( let i= this.featureGroups.length-1; i>=0; i--) { if( this.featureGr ...

Using setState as a parameter in a personalized hook in React/Next.js while incorporating TypeScript

I encountered an issue with the following code snippet: import { useState, useEffect } from "react"; type Props = { setState: (value: string) => void; }; const useSomeCustomHook = ({ setState }: Props) => { useEffect(() => { se ...

Issue with Angular2 Property Change Notification

I have a directive called app.service.ts that holds the state data of the app. I'm using this directive in other components to access and modify the app state, which is functioning correctly. However, I encounter an error when I attempt to bind a pro ...

After updating to Angular 7, an error was encountered: "TypeError: Unable to execute map function on ctorParameters"

After updating my Angular project to version 7, I encountered a new issue. When running "ng serve --open" from the CLI, I received the following error message: Uncaught TypeError: ctorParameters.map is not a function at ReflectionCapabilities._own ...

Best approach for managing Union Types in Angular 16 Templates / Utilizing Type Inference?

Currently, I'm immersed in a project using Angular 16 where my focus lies on applying a reactive declarative method. Oftentimes, I find myself working with Observables that emit varying data types - either successful data or an error object. Each ret ...

Exploring the World of Micro-Frontends with the Angular Framework

I am conducting research on the best methods for transitioning a large single-page application into a micro-frontend architecture. The concept: The page is made up of multiple components that function independently Each component is overseen by its own ...

What is the best way to connect a series of checkboxes within a form utilizing Angular?

I created a form with checkboxes that allow users to select multiple options. However, when I submit the form, instead of receiving an array of objects representing the checked checkboxes, I'm not getting anything at all. Here is what I see in the co ...

Angular jsonp.get request was denied despite receiving a status code of 200 indicating success

I have been attempting to access my basic web API created in Jersey, which returns the following data: [ { "id": 1, "name": "Facebook", "userName": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f4 ...

Koffi organized a collection of structured arrays

I am currently using koffi 2.4.2 in a node.js application from koffi.dev and up until now, everything has been running smoothly. However, I have encountered an issue with integrating a native C++ library method that requires a parameter struct defined as f ...

The css values for component _nghost-c0 in an Angular application

Recently, I've been delving into Angular 5 and couldn't help but notice the peculiar html tags with ng generated attributes like _nghost-c0 and _nghost-c1... This got me wondering, what exactly do these attributes signify? [_nghost-c3] .employee ...

The soft keyboard on Android devices may be obscured by an input field when using Cordova

When I use the text input field on my Android phone, the soft keyboard covers the input field. My app is built with Cordova and Angular 6. I have attempted the following solution: <preference name="Fullscreen" value="false" /> <edit-config file ...

NextJS Typescript Player

Encountering an issue during the build process, specifically with the error in audioRef.current.play(). The error message indicates that there is no play function available. I attempted to use an interface but it seems to not accept boolean values. Could ...

Sending data to child components in Ionic

I am currently utilizing Ionic's router-outlet to navigate between a parent page and three children pages: parent.page.html <ion-content> <ion-router-outlet></ion-router-outlet> </ion-content> parent-routing-module.page.t ...