Convert a collection of observables containing events to an observable array of events

I am working on creating a function that merges all event streams generated from an array of data channels and emits any event received from them.

Below is the initial function:

  private dataChannels: BehaviorSubject<RTCDataChannel[]> = new BehaviorSubject([]);
  // The datachannels array will be populated at some point
  ...

  public on(): Observable<Event> {
    const eventStreams = this.dataChannels.value.map((channel) => fromEvent(channel, 'message'));
    return merge(...eventStreams);
  }

However, I realized that the issue with the current function is that it does not utilize new values emitted to the data channels BehaviorSubject.

As a result, I started developing the following function:

  const allEvents = this.dataChannels.pipe(map((channels) => channels.map((channel) => fromEvent(channel, 'message'))));

  return merge(...allEvents);

The problem arises when allEvents ends up being of type

Observable<Observable<Event>[]>
, which is not compatible with the merge function. How can I convert the observable to type Observable<Event>[]?

Answer №1

To optimize your code, consider merging all the Observables received in a BehaviorSubject. There appears to be an issue with lingering subscriptions to channels even after they are removed from dataChannels. I suggest creating a new property named newSubscription$. Emitting this property will cause all subscriptions created using fromEvent to unsubscribe.

Give this solution a try:

    newSubscription$ = new Subject();
    this.dataChannels.pipe(
        tap(() => {
            this.newSubscription$.next();   // terminate existing subscriptions
            this.newSubscription$ = new Subject(); // and await for new ones
        }) 
        switchMap((allChannels) => {
        const fromEvenObs = allChannels.map(c => fromEvent(c, 'message').pipe(takeUntil(newSubscription$)));
        return merge(...fromEvenObs);
    })).subscribe((data) => { // data obtained from any event });

UPDATE:

Due to the usage of switchMap(), it is not necessary to have an additional observable to handle unsubscribing from events when new data is received by dataChannels. The following modification should suffice:

this.dataChannels.pipe(
    switchMap((allChannels) => {
        const fromEvenObs = allChannels.map(c => fromEvent(c, 'message'));
        return merge(...fromEvenObs);
})).subscribe((data) => { // data from events });

Answer №2

To achieve this functionality, one can utilize the `mergeAll` operator according to the documentation's guidance that states `mergeAll subscribes to an Observable that emits Observables. Each time it observes one of these emitted inner Observables, it subscribes to that and delivers all the values from the inner Observable on the output Observable.`

Additionally, the `from` operator can be used to emit each observable within an array of observables.

const allEvents = this.dataChannels.pipe(
   map((channels) => from(channels.map((c) => fromEvent(c, 'message'))),
   mergeAll();
);

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

Managed the double-click event to select Snap.svg text

I am currently utilizing the snapsvg library for a project where I am implementing the dblclick event to trigger a browser window alert. However, when clicking on the svg canvas, not only does the alert pop up but some text on the canvas also gets selected ...

Adjust the text color of ASP.Net Label based on the presence of a hyphen

I need help changing the text and font color of my ASP.net label based on its content. The label displays a percentage change, and I want negative numbers to be shown in green and positive numbers in red. However, when I try to implement this, I keep enc ...

Tips for customizing the Electron title bar and enabling drag functionality

Currently, I am embarking on an electron project and my goal is to incorporate a unique custom frame at the top. Does anybody possess knowledge on how this can be achieved? To further clarify, here is a visual representation of what I envision for the cust ...

Having trouble getting dynamic values to render properly in Ionic select? Find a solution in Ionic 4

Encountering an issue with Ionic 4 and ion-select. The problem arises when attempting to bind data, specifically when preselecting data. In this scenario, the ion-select element fails to render properly. <ion-item class="transparent"> ...

Guide to utilizing JavaScript and JQuery for retrieving a PDF from a specific URL and subsequently uploading the file to another website

I have a link to a PDF file: http://www.example.com/HelloWorld.pdf My objective is to download the file using JavaScript/JQuery/AJAX and temporarily store it in the browser, without saving it on the user's machine. Then, I want to POST it to . To ac ...

Error: Attempting to access the 'firstChild' property of a null object when trying to display a street view panorama with Vue.js

Looking to integrate a street view panorama using the Google Maps API in my VueJS project. I followed the documentation provided by Google maps here, and here is the basic template: <div id="map"></div> <div id="pano"></div> Her ...

Javascript: Comparing Equality of two Objects/ Arrays

Consider two objects with the same property: var obj1 = {name: 'John'}, obj2 = {name: 'John'}; Result: obj1 == obj2; and obj1 === obj2; both return false The same holds true for arrays: var arr1 = [1, 2, 3], arr2 = [1, ...

React JS, cumulative points total

As a newbie in the world of React js, I am currently developing an application that allows users to update points for each team member within a team. The increment and decrement functionalities are working smoothly, thanks to the assistance I received here ...

Presenting quiz questions using javascript

Currently, I am following the learning path on javascriptissexy.com and facing a challenge with displaying quiz questions in the best way possible. As a beginner student of JavaScript, my question is about how to approach developing the behavior of a quiz ...

AngularJS fails to recognize Iframe element during REST request

I'm having trouble with my webpage only reading the Iframe tag. It's sending the content correctly according to Postman. Postman is giving me this content: "Conteudo": "<p>Test iframe:</p>\n\n<p><iframe framebord ...

Create dynamic animations using AngularJS to transition between different states within an ng-repeat loop

Here's a simplified explanation of my current dilemma: I have an array containing a list of items that are being displayed in an Angular view using ng-repeat, like... <li ng-repeat="item in items"> <div class="bar" ng-style="{'width ...

Update the input component's typing area line color from its default shade

Is there a way to customize the color of the line in the typing area for the input component? I haven't been able to find any information on using Sass variables or another method to achieve this. For reference, here is a Plunker example <ion-it ...

Activate a mouse click event based on user input in a Shiny

I am currently developing a shiny app that includes a plotly sunburst chart. Once I provide the correctly formatted dataframe, I need to interact with the sunburst chart by clicking on it to "drill-down." Is there a way to replicate this mouse click act ...

Troubleshooting a VueJS Problem: Updating $data in the mounted hook

Revision This snippet of Component.vue was extracted from a larger web application where I made a mistake that had significant consequences, all because of a small change I didn't initially notice. An important distinction exists between the followi ...

Occasionally, altering the visibility of an element right before submitting a form in Safari may not be effective

Below is the HTML element I'm using to show a loading spinner in my app, with mostly Bootstrap classes: <div id="loadSpinner" class="overlay d-flex justify-content-center invisible"> ... </div> Here is the form on vi ...

Looking to attach a listener to an element within a modal once it has finished rendering?

Upon clicking a button, a modal window appears. The controller assigned to the modal contains a list of element IDs that need listeners assigned. However, when the controller initializes, the modal has not yet rendered, causing the elements requiring liste ...

Adding query parameters to an Angular route

In my app's routing module, I have set up the following routes: const routes: Routes = [ { path: "", redirectTo: "/smart-parking/dashboard", pathMatch: "full" }, { path: "locations-create", component: AddLoc ...

Having trouble importing components from the module generated by Angular CLI library

After creating a simple Angular library using CLI with the command ng g library <library-name>, I encountered an issue while trying to import a component from its module. In my app module, I added components.module to the imports array and attempted ...

nighttime surveillance struggled to locate the element based on its identifier

On my page, I have the following HTML DOM structure and I am using Nightwatch to write test cases. <td class="GPNWDJGHV" id="gwt-debug-MenuItem/mongo-true">Mongo Extension</td> When trying to select the element using its ID with the '#&a ...

What is the proper way to set up state with localStorage in Nuxt.js when using Universal Rendering?

Unique Situation In my unique setup, I have a specific flow that involves storing a token in localStorage, even though I know it's not the recommended practice. Every time my Nuxt App is launched, I need to retrieve the token from localStorage, valid ...