When utilizing mergeMap() in conjunction with a subject, the takeWhile() condition set on the observable being merged is disregarded

I am currently exploring ways to halt an observable. After studying blesh's post on github at https://github.com/ReactiveX/rxjs/issues/1542, I believe I am making progress. However, when I apply a switchMap() from my pauser Subject to the takeWhile() on my observer, it seems that the takeWhile() is being disregarded.

The following section functions correctly:

export class CompositionService {
    cursor = -1;
    pauser = new Subject();
    interval;
    init = (slides) => {
        let waitUntil = 0;
        return this.interval = Observable
            .range(0, slides.length)
            .mergeMap((i) => {
                let next = Observable.of(i).delay(waitUntil);
                waitUntil += !!slides[i]["duration"] ? slides[i]["duration"] : 0;
                return next;
            })
            .scan((cursor) => {
                return this.cursor = cursor = slides[cursor + 1] ? cursor + 1 : -1;
            }, this.cursor)
            .map(cursor => slides[cursor])
            .takeWhile((slide) => {
                return !!slide;
            });

    };
    // these methods are not called for this sample
    play = () => {
        this.pauser.next(false);
    };
    pause = () => {
        this.pauser.next(true);
    };
};

This part works as expected when executed like this:

it("should subscribe to init", (done) => {
    slides.forEach((slide, i) => {
        if (slide.duration) {
            slide.duration = slide.duration / 100;
        }
    });
    composition.init(slides).subscribe(
        (slide) => {
            console.log(slide);
        },
        (err) => {
            console.log("Error: " + err);
        },
        () => {
            done();
        });
});

Although the previous example operates as intended, the interval Observer never terminates when I introduce some additional logic:

export class CompositionService2 {
    cursor = -1;
    pauser = new Subject();
    interval;
    init = (slides) => {
        let waitUntil = 0;
        this.interval = Observable
            .range(0, slides.length)
            .mergeMap((i) => {
                let next = Observable.of(i).delay(waitUntil);
                waitUntil += !!slides[i]["duration"] ? slides[i]["duration"] : 0;
                return next;
            })
            .scan((cursor) => {
                return this.cursor = cursor = slides[cursor + 1] ? cursor + 1 : -1;
            }, this.cursor)
            .map(cursor => slides[cursor])
            .takeWhile((slide) => {
                return !!slide;
            });
        return this.pauser
            // leaving commented for clarity of the end game
            // .switchMap( paused => paused ? Observable.never() : this.interval );
            // however, not even a straight forward switchMap is yeilding the expected results
            .switchMap( paused => this.interval );            
    };
    play = () => {
        this.pauser.next(false);
    };
    pause = () => {
        this.pauser.next(true);
    };
};

When used in this manner:

r should subscribe to init", (done) => {
    slides.forEach((slide, i) => {
        if (slide.duration) {
            slide.duration = slide.duration / 100;
        }
    });
    composition.init(slides).subscribe(
        (slide) => {
            console.log(slide);
        },
        (err) => {
            console.log("Error: " + err);
        },
        () => {
            //I never get here!!!!!
            done();
        });
    // kickstart my heart!
    composition.play();
});

Can anyone provide insight into what might be going wrong here?

Answer №1

The outer stream is not being completed in your current implementation. In the initial version, the completion is triggered by the takeWhile operator finishing the stream. However, when you nest this inside a switchMap, only the inner stream is being completed because the outer stream (a Subject) never reaches completion. This results in an endless stream from the subscriber's perspective.

If you wish to terminate the stream, you must end it at some point. For example:

composition.init(slides)
  .take(3)
  .subscribe(
    (slide) => {
        console.log(slide);
    },
    (err) => {
        console.log("Error: " + err);
    },
    () => {
        //I never get here!!!!!
        done();
    });

I am uncertain if Rx is the best tool for this scenario, as streams are not intended to be paused. Stopping the Observable from continuing to propagate is not feasible. You may have observed the complexities of storing state during pauses, so exploring alternatives like generators or a library such as IxJS could be worth considering. But that's just my opinion.

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

Error: Unable to retrieve the value of a null property | ReactJS |

There are two textboxes and one button designed as material UI components. </p> <TextField id="chatidField" /> <br /> <p> <code>Enter Your Name:</code> <hr /> & ...

Tips on returning the array

I've been struggling to figure out how to extract the 'sheetsArray' from the code snippet below so that I can use it for various tasks. Despite my efforts and hours of searching online, I haven't been able to find a solution. It seems l ...

Mongoose failing to populate associated records from a different collection

Currently, I am working on a project focused on tracking rewards for my children. This project is serving as a hands-on learning experience for me in Node.js and MongoDB/Mongoose. However, I have encountered an issue which I suspect could be due to transit ...

Enhancing User Experience with Cascading Dropdown Menus in MVC 5

I've been working on this project for a few days now, trying to get Cascading Dropdownlists to function properly. I'm having an issue where my State dropdownlist is not populating and no error message is displayed when the Ajax call fails. What c ...

"Handling API Calls with AngularJS: Dealing with the [object object] Response

Looking for some guidance on pulling a list of articles from the NPR API. I have a functioning URL that returns JSON data. However, in my controller code, I seem to be having trouble accessing the object. When I use console.log to check, it just shows [obj ...

The issue in AngularJS 1.4 where the select element value is not binding due to a type mismatch

My ng-model has a value assigned to it, but it is not binding with the selected element. <select data-ng-model="myval"> <option value="? number:2 ?"></option> <option value="2" class="ng-binding">Value 1</option> <op ...

Getting the chosen option from a dropdown list mapped in ReactJS

I am working on a dropdown select option that is linked to the data of an array object called 'template_titles'. Currently, the value in the dropdown corresponds to the title in the object. My goal is to be able to extract and use the selected va ...

Expanding the Capability and Retrieving Data from the Parent Class Using JQuery

How can I access the super object while extending objects with $.extend? I need to extend an object, replace a method, and then invoke the overridden superclass method within the subclass method. ...

Guide to accessing a server file directly from the client's web browser

Hey Team, I have a requirement for the browser to read a property file from the server. To achieve this, I am using JQuery/AJAX as shown below. <script> var properties = null; $(document).ready(function(){ $.ajax({url:"demo_test.txt",success:fun ...

JavaScript not functioning properly with 'required' validation

pushData = []; //+ button when clicked function myFunction() { var custOfficeId = document.getElementById('customOfficeId').value; var custOfficeName = $("#customOfficeId option:selected").text(); var fromDate = document.getElementByI ...

Transforming all commas to plus signs in a JavaScript codebase for the entirety of

Currently, I am using winston for logging and have created a common method to log throughout the project. However, I am facing an issue with many logging statements that look like this: logger.info("here is the data" , data) The problem arises when trying ...

Checkbox acts like radio buttons in JavaScript

Currently, I have a unique setup where a table is generated dynamically based on the user's selection from a dropdown. Within this table are three checkboxes per row, with a limit of 2 checkboxes that can be checked per row. The behavior of Checkbox ...

Refresh the Morris chart using jQuery after a .NET MVC post request

In my .NET Controller action, I have written code to fetch specific time zone and group data based on that time zone. The code looks like this: [HttpPost] [ActionName("FetchTimeZone")] public ActionResult FetchTimeZone(string timeZone) ...

The content is overflowing outside the boundaries of the div, yet there is no

I am currently utilizing jQuery to dynamically load the content of a text file into a div element. However, when the content exceeds the dimensions of the div, no scroll bar is displayed. Here is the HTML structure: <!DOCTYPE html> <html lang=" ...

Utilizing Parallax.js within the React Framework

Just starting out with React and attempting to integrate the Parallax.js library into my project. I've completed the installation using npm, imported the library, and followed this helpful discussion related to my query. However, I'm encounterin ...

React is failing to display identical values for each item being mapped in the same sequence

I have implemented some standard mapping logic. {MEMBERSHIPS.map((mItem, index) => ( <TableCell className="text-uppercase text-center" colSpan={2} padding="dense" ...

JavaScript validation controls do not function properly when enabled on the client side

Following the requirements, I have disabled all validation controls on the page during the PageLoad event on the server side. When the submit button is clicked, I want to activate the validations and check if the page is valid for submission. If not, then ...

Tips for concealing JavaScript code while inspecting elements with AngularJS

Is it possible to display minified JavaScript code when using Angular and inspecting elements? ...

Enhancing React components with customized features through the use of mixins in material-ui

I'm currently working on customizing a textfield component in Material-ui using React. Based on the details provided on this page: To personalize the colors of different parts of the text-field, you can utilize various mixins. It's recommende ...

Difficulty encountered when consolidating intricate data attributes into a single array

I have a task to tackle in the code snippet below. My goal is to collect all the data in the age attributes and store them in a single array, formatting it as shown here: output = [48, 14, 139, 49, 15, 135, 51, 15, 140, 49, 15, 135, 51, 15, 140, 52, 16, ...