The operator is being invoked multiple times beyond originally anticipated

I am currently working on developing code that paginates a result set using the expand operator until a specific number of resources have been fetched. Below is the code snippet I have written so far (excluding the actual async call logic):

import { Observable } from 'rxjs';

const items = [
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
    [21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
];

const call = () => {
    console.log('#call');

    const batch = items.shift();

    if (batch) {
        return Observable.of(batch).delay(100);
    }

    return Observable.empty();
}

const o$ = call().expand((values) => {
    console.log('expansion');
    return call();
}).flatMap((val: any) => val);

const log = (prefix: string) => (...args: any[]) => console.log(prefix, ...args);

o$.take(9).subscribe(log('next'), log('error'), log('complete'));

The output is not as desired:

#call
takeWhile.ts:26 next 1
takeWhile.ts:26 next 2
takeWhile.ts:26 next 3
takeWhile.ts:26 next 4
takeWhile.ts:26 next 5
takeWhile.ts:26 next 6
takeWhile.ts:26 next 7
takeWhile.ts:26 next 8
takeWhile.ts:26 next 9
takeWhile.ts:26 complete
takeWhile.ts:22 expansion
takeWhile.ts:10 #call

Although I receive the 9 items as requested with take, the stream completes, but an additional expansion occurs and the mock async API is called again.

Is there a way to modify my code to prevent this extra recursive iteration and make it less eager?

Answer №1

The issue you are encountering is part of the expected behavior: the expand function is called before take, resulting in the following sequence:

  • We obtain the first value
  • expand is triggered and the call is initiated
  • Subsequently, the entire observable is immediately unsubscribed from

Consequently, in order to address this issue, it is necessary to make the recursive call asynchronous to allow the take function to unsubscribe prior to the call being executed. The simplest solution appears to be replacing return call(); with either return timer(4).map(call); or return defer(call);, which somehow addresses the problem :/.

View this example in practice

Overall, it is important to introduce a "pause" or "gap" to allow the limiter to take effect and unsubscribe.

I trust that this information is beneficial to you

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

Can an IonChange event be triggered from a component in Ionic 3?

Currently, I am working on developing an application that involves multiple forms. In most instances, when a user navigates back from the Confirmation view to the Form view to modify their entered data, it is essential for the form to retain the previously ...

The ES6 import feature conceals the TypeScript definition file

I currently have two definition files, foo.d.ts and bar.d.ts. // foo.d.ts interface IBaseInterface { // included stuff } // bar.d.ts interface IDerivedInterface extends IBaseInterface { // more additional stuff } Initially, everything was funct ...

Troubleshooting Angular 2: Instances of Classes Not Being Updated When Retrieving Parameters

I am facing an issue with the following code snippet: testFunction() { let params = <any>{}; if (this.searchTerm) { params.search = this.searchTerm; } // change the URL this.router.navigate(['job-search'], {q ...

Exploring the use of @HostListener in Angular for handling drop events

I am currently working on developing a directive for drag and drop functionality with files. I have successfully implemented the dragenter and dragleave events, but for some reason, the drop event is not being recognized. @HostListener('drop', [ ...

Make sure to include all enum type values within the function's body to ensure comprehensive coverage

I am defining an enumeration called ApiFunctions with values like "HIDE", "SET_READ_ONLY", and "DESCRIPTION". Also, I have a type ValueOfApiFunction that should include all values of ApiFunctions. Additionally, I have a logic that listens for messages on ...

Elements are receiving CSS properties from other elements within the same component

I'm encountering an issue with my components: 1. I cannot seem to style html and body in signin.component.css for some reason. The workaround I found was using: encapsulation: ViewEncapsulation.None ==> This works perfectly However, when I switch ...

Is there an issue with integrating Bootstrap with Angular 6?

npm install bootstrap Update the angular.json file: "styles": [ "node_modules/bootstrap/dist/css/bootstrap.min.css", "styles.scss" ] Include the Bootstrap CSS directly in your src/style.css: @import '~bootstrap/dist/css/bootstrap.min.css'; A ...

Utilizing a setup module for configuration purposes

In the process of developing my angular application, I have integrated several external modules to enhance its functionality. One crucial aspect of my final application is the configuration classes that store important values like URLs and message keys us ...

When attempting to incorporate a third-party library into Angular2 using the CLI, the process did not go as smoothly as anticipated

Trying to integrate a third party JavaScript library sockJS into my Angular2 project... system.config.ts: /** Mapping relative paths to URLs. */ const map: any = { 'sockjs-client': 'vendor/sockjs-client/' }; /** Configuration for use ...

Javascript operations for duplicating and altering arrays

In my Angular application, I am working with an array called subAgencies that is connected to a datasource. I need to implement 2-way binding on this array. Currently, I have a method in place where I copy the contents of the original array to a new one, ...

The error message "Cannot read property of undefined" is often caused by an issue with the cdkDropList

Currently, I am utilizing the cutting-edge Angular 7 Material CDK drag-drop functionality to smoothly move items from one list to another. Visually, everything seems to be working flawlessly during these movements. However, I encountered an issue when atte ...

A powerful trio: Axios, Typescript, and Promises

I am facing a TypeScript dilemma. I have a REST method that is being called within my http library by Vue action. I want the resolve() method to return the typed array, but if I do not convert it within the action.ts "then" method, I get a '.length do ...

Communicating from JQuery-UI to Angular 6 using callbacks

I incorporated the jQuery-UI MonthPicker into my Angular 6 application, and now I am looking to trigger an Angular action whenever the date changes: ngOnInit() { $(document).ready(function() { $('#myMonthPicker').MonthPicker( ...

Is there a way for me to dissect a segment of the source map produced by source-map-explorer without any reference?

I'm currently working on an Angular 12 application and I've noticed that the bundle size is unexpectedly large, even though there are only a few components in the application. After using source-map-explorer to analyze the bundle, I discovered th ...

Encountering an Angular schematics issue while utilizing an external schematic ng-new, the specified version is

Attempting to develop a schematic that utilizes the angular ng-new as the initial call and another schematic to add a prettier file to the new project. Upon executing the command, an error is encountered: Data path "" must have required property 've ...

WebStorm provides alerts for objects, types, and directives within Angular, yet they function properly

Why is WebStorm displaying warnings for objects, types, and directives in Angular Template HTML even though they are functioning correctly? Despite the fact that all types and Angular directives in the HTML structure are working fine within Angular on Web ...

Typescript: Assigning Variables Without Prior Declaration

In my upcoming Node.js application, I decided to use TypeScript for development. However, I encountered a perplexing issue while working on the code below: class AuthService { public async init(req: Request, res: Response) { let user: IUser | ...

Making an Angular 6 HTTP GET call using HTTP-Basic authentication

When attempting to access a URL that requires Basic Authentication, and returns JSON data, what is the proper way to include my username and password in the following HTTP request? private postsURL = "https://jsonExample/posts"; getPosts(): Observable& ...

Using Karma-Jasmine to Import Spy without anyImplicitAny

If I include the configuration setting noImplicitAny in the tsconfig.json file of my Angular 4+ project: "noImplicitAny": true, ...and then try to import and use Spy in a unit test: import { Spy } from "karma-jasmine"; I encounter this console error wh ...

Lazy-loading modules in SSR Angular 8 applications are currently unspecified

I am currently in the process of setting up my Angular 8 application to work with server-side rendering (SSR). However, I am encountering some undefined errors in webpack when running my application using ng serve, especially with lazy-loaded modules. Ever ...