Combining two RxJs observables to create selectable options for a material drop-down menu

I'm encountering issues while attempting to combine two different observables and display the results in a Material Select component.

This example (created using the Material docs tool) demonstrates what I'm trying to achieve. However, the options are not being shown.

In my current code (on my local machine), the problem I'm facing is: the first Observable passed to the concat operator gets subscribed to and all items are displayed in the Select. However, I suspect that the first Observable never completes. It seems like the material-select component is not "completing" the first Observable, thus causing the concat operator to not subscribe to the next Observable while the first one remains incomplete, as mentioned in the documentation:

Note that if some input Observable never completes, concat will also never complete and Observables following the one that did not complete will never be subscribed.

What I require is to take two different Observables (each with different data), combine them using concat (or any other operation), and ultimately display all the data merged as options in a single select component.

For reference, here's the code snippet to ensure it's not lost in the future:

// Component:
import { Component, Input } from '@angular/core';
import { from } from 'rxjs';
import { concatWith } from 'rxjs/operators';

interface Option {
  value: number;
  label: string;
}

@Component({
  selector: 'select-overview-example',
  templateUrl: 'select-overview-example.html',
})
export class SelectOverviewExample {
  @Input()
  options$: any;

  constructor() {}
  ngOnInit() {
    // Pretend this data is coming from API 1
    const sourceA$ = from([
      { value: 1, label: 'Value 1' },
      { value: 2, label: 'Value 2' },
      { value: 3, label: 'Value 3' },
    ]);

    // And this data is from API 2
    const sourceB$ = from([
      { value: 4, label: 'Value 4' },
      { value: 5, label: 'Value 5' },
      { value: 6, label: 'Value 6' },
    ]);

    // Concatenate the data from both observables and display all options in a Select component:
    this.options$ = concatWith(sourceA$, sourceB$);
  }
}

And here's the template:

<h4>Basic mat-select</h4>
<mat-form-field appearance="fill">
  <mat-label>Select some value:</mat-label>
  <mat-select>
    <mat-option
      *ngFor="let option of (options$ | async)"
      [value]="option.value"
    >
      {{option.label}}
    </mat-option>
  </mat-select>
</mat-form-field>

Answer №1

To gather data from multiple observables, you can utilize the combination of the merge function along with the scan operator in the following manner:

import { from, merge } from 'rxjs';
import { scan } from 'rxjs/operators';


const sourceA$ = from(/* ... */);
const sourceB$ = from(/* ... */);

merge(sourceA$, sourceB$)
  .pipe(
    scan((acc, value) => {
      acc.push(value);
      return acc;
    }, [])
  )
  .subscribe((value) => console.log(value));

See StackBlitz Example

In this demonstration, you can substitute merge with concat and the functionality remains intact. If the sequence of values is crucial and you prefer to receive all values from sourceA$ before moving on to sourceB$, then using concat would be more appropriate than merge.

In response to your feedback...

It seems that material-select does not "complete" the initial Observable

It is not the duty of material-select to finalize the source Observable. The responsibility lies with the source Observable to complete itself. material-select lacks the ability to determine when the source Observable has finished emitting values unless the source Observable completes on its own.

Answer №2

To achieve a clean and effective solution, you can utilize the combination of forkJoin followed by merging two arrays:

this.combinedOptions$ = forkJoin([sourceX$, sourceY$]).pipe( // executes both concurrently
  map(result => {
    const dataX = result[0]; 
    const dataY = result[1]; 
    return [...dataX, ...dataY]; // merge two arrays using the spread 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

The css-loader is missing the required dependency peer Webpack5, causing a resolution error

Recently, I've ventured into the world of JavaScript and I'm looking to incorporate vue-audio-visual into my project. However, I encountered a perplexing error in my node console that seems unrelated. The npm error message reads as follows: code ...

Guide to adding a CSS class to an Ionic2 toast

i found a helpful resource on applying cssClass to my toast component. within my HTML, I have buttons: <button ion-button (click)="presentToast()"> toast</button> Here is the code snippet from my .ts file: presentToast() { let toast = t ...

An error was encountered stating "TypeError: Unable to call function on undefined object while attempting to utilize a JSON object

My current setup involves using D3js with MongoDB and AngularJS to showcase my data. Everything works smoothly until I decide to give my JSON array a name. Suddenly, Angular starts throwing errors at me and I'm left confused as to why. Here is the or ...

Calculating distinct values within a single key in an object

My goal is to track the occurrences of four specific string values within the same key. The issue lies in my struggle with adding multiple counters. While the first counter successfully tracks the initial condition, subsequent conditions within the if/els ...

What is the best way to extract URL query parameters and store them in a MySQL database using Node.js and Express

I am working on a project where I need to store specific information like names and widths from the URL query into my MySQL database. The format of the URL query should resemble this: /register?name=XXXX&width=###.### However, I seem to be facing ch ...

Python Scrapy: Extracting live data from dynamic websites

I am attempting to extract data from . The tasks I want to accomplish are as follows: - Choose "Dentist" from the dropdown menu at the top of the page - Click on the search button - Observe that the information at the bottom of the page changes dynamica ...

Guide to slicing strings specifically with numerical characters at the end

I've encountered a challenge. I need to slice the last two characters in a string, but only for strings that contain numbers. I attempted using "nome": element.nome.slice(0,-2) and now I require some sort of validation. However, figuring out how to do ...

Using three.js to establish an Image for Particle

I am looking to make some changes to this demo: Instead of having colored particles, I want to assign an image to each one. Should I use a cube for this purpose? Or is there a way to use an image with Vector3? Here is the code for the example: i ...

Resposiveness of force-directed graph is lost

const container = document.getElementById("container"); const svgElement = d3.select(container).append("svg") // Get the width and height computed by CSS. let width = container.clientWidth; let height = container.clientHeight; const colorScale = d3.scale ...

Angular UI-Router has a quirk where it may execute a controller twice upon loading if it is defined within the

Every time I run the code in my controller, it seems to be executed twice, resulting in duplicate outputs in the console.log window of Chrome Dev Tools. questions.html <div ng-controller="questionController as vm"> </div> questionController. ...

Tips for troubleshooting when document.queryselector isn't functioning properly in NextJS for server-side rendering (SSR)

I encountered an issue with my circular progress bar code on a Next.js page. Whenever I try to update the "progressEndValue" variable to 67, it triggers a page refresh but doesn't reflect the new value on the progress bar. Instead, I receive the follo ...

unable to receive the data transmitted by the socket.io client

I hit a roadblock while trying to follow the tutorial on socket.io. I'm currently stuck on emitting events. Previously, I successfully received the console logs for user connected and user disconnected. However, when it comes to emitting messages, I a ...

React - the use of nested objects in combination with useState is causing alterations to the initial

After implementing radio buttons to filter data, I noticed that when filtering nested objects, the originalData is being mutated. Consequently, selecting All again does not revert back to the original data. Can anyone explain why both filteredData and orig ...

How can I obtain the download link for an image that has been resized using Node.js in Google Cloud Functions?

I have recently started exploring node js and google cloud functions. Successfully, I can resize an image to create a thumbnail. However, I am stuck at finding the download URL for the newly generated thumbnail. Below is the code snippet: exports.gener ...

A Nuxt plugin that integrates a separate website into the serverMiddleware

The concept Imagine having a main Nuxt website just like any other. Now, think about adding my module to your project. This module will then introduce a subdomain "admin.example.com" to your project, creating a fully functional Nuxt-based website that ope ...

Is there a way to trigger a modal popup when hovering over a Bootstrap 5 card?

After coming across a handy template online, I decided to implement a modal pop-up feature when hovering over cards using Bootstrap 5. Here's what I have so far: class SavedEpisodes extends Component { $(function() { $('[data-toggle=&qu ...

What is preventing the table from extending to the full 100% width?

Displayed above is an image showing an accordion on the left side and content within a table on the right side. I have a concern regarding the width of the content part (right side) as to why the table is not occupying 100% width while the heading at the ...

After installing Node.js on a Windows machine, the program 'npm' is not identified as an internal or external command, and cannot be executed as an operable program or batch file

I have been searching for a solution to this problem, but none of the suggestions I found seem to work for me. I am currently using a Windows 10 Laptop where I do not have administrative rights. My goal is to run my Angular + NodeJS application on this ma ...

Can the hexadecimal value from an input type color be extracted and used to populate form fields that will then be displayed in a table after submission?

Hello everyone, I'm new to this platform and seeking guidance on how to improve my post! I recently created a CRUD app using Angular. It consists of a basic form with 4 fields, a color picker using input type='color', and a submit button. U ...

Using Vue.js with Vue Router to handle login functionality and automatically refreshing data

I am currently working on a Vue.js application and have successfully implemented authentication functionality, including checking if the user is logged in. After logging in, I want to fetch some data and store it in localStorage. However, I have encounter ...