Switching between API requests through a live feed

Hey there:

import Rx from 'rxjs';

function mockApi(endpoint, time, response) {
  return new Rx.Observable(observer => {
    console.log(`${endpoint}: Request initiated.`)
    let active = true;
    const id = setTimeout(() => {
      console.log(`${endpoint}: Response received.`)
      active = false;
      observer.next(response);
      observer.complete();
    }, time);
    return () => {
      if(active) console.log(`${endpoint}: Cancel operation.`)
      clearTimeout(id);
    }
  })
}

function fetchFromApi() { return mockApi('Search', 4000, "This is a result of the search."); }


//============================================================

const messages$ = new Rx.Subject();

const trigger$ = messages$.filter(m => m === 'toggle');

const completedSearch$ = trigger$.flatMap(() => 
  fetchFromApi().takeUntil(trigger$)
);

completedSearch$.subscribe(m => console.log('Subscriber:', m))

setTimeout(() => {
  // Initiates API call.
  trigger$.next('toggle'); 
}, 2000)

setTimeout(() => {
  // Cancels ongoing API call without starting a new one.
  trigger$.next('toggle'); 
}, 3000)

setTimeout(() => {
  // Starts a new request.
  trigger$.next('toggle'); 
}, 9000)

I aim to initiate and terminate an API call using the same trigger$ signal. The problem lies in how the code currently functions - it triggers a new API call each time. I want it to only halt an existing call when in progress, not commence a fresh one. Perhaps there's a need to detach the outermost flatMap subscription from the trigger$ stream while fetchFromApi() runs. Any suggestions on restructuring the code for this desired behavior? What's the ideal RxJS approach here?

UPDATE: After further exploration and referencing user guides, I arrived at this solution:

const completedSearch$ = trigger$.take(1).flatMap(() =>
  fetchFromApi().takeUntil(trigger$)
).repeat()

Operates as intended. Still seems slightly enigmatic. Is this the typical RxJS methodology to resolve such scenarios?

Answer №1

It seems like the solution provided will only work on a single occasion due to the usage of take(1). An alternative approach could be:

const searchDone$ = toggle$
    .let(observable => {
        let pending;

        return observable
            .switchMap(() => {
                let innerObs;

                if (pending) {
                    innerObs = Observable.empty();
                } else {
                    pending = innerObs = apiSearch();
                }

                return innerObs.finally(() => pending = null);
            });
    });

The use of let() is limited to encapsulating pending without defining it in the parent scope. The switchMap() operator automatically unsubscribes without requiring take*().

When applying your test with setTimeout, the expected output will be as follows:

Search: Request.
Search: Cancel.
Search: Request.
Search: Response.
Subscriber: This is a result of the search.

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

Display various elements depending on the size of the screen within Next.js

My goal is to display a component differently depending on whether the screen width is less than 768p or not. If the width is under 768p, I want to show the hamburger menu. Otherwise, I want to display the full menu. This is the code snippet I am using. ...

The Google Maps API allows all markers to be connected to a single infowindow

I've been grappling with this issue for some time now, but I just can't seem to find a solution! I'm retrieving data from a database in Laravel using Ajax and then attempting to display infowindows for each marker on Google Maps. The markers ...

Passing a reference to a react functional component (react.FC) results in a type error: The property ref is not recognized on the type 'IntrinsicAttributes & Props & { children: ReactNode}'

Currently, I am working on mastering the utilization of forward refs. In a functional component (FC), I am trying to initialize all my refs and then pass them down to its child components so that I can access the canvas instances of some chartjs charts. Ho ...

How can I ensure that the scripts returned in HTML via AJAX are executed when using $.load()?

I have been trying to make an AJAX call and receive a partialView which contains some script that needs to be executed. I did some research and learned about the "eval" method, but then discovered that the $.load() method should handle this for me. Howeve ...

Navigate to the adjacent IDs

I have multiple sections with varying content and links (previous and next) to navigate to the next section. Initially, everything functions properly. However, when adding a new section in between existing ones, I am required to update all the ids to ensu ...

Is the JavaScript file not being stored in the cache?

As I work on optimizing my web application, I am facing a challenge with a javascript file size of approximately 450K even after compressing it. While I intend to redo the javascripting in due time, for now, I need to go live with what I have. Initially, I ...

What is the best method for creating a fade effect on a div background?

I am trying to animate a div with the id #test from a 0 opacity background to an opacity of 0.7 using CSS rgba values, but for some reason, the .animate function is not working as expected. Here is my CSS: #test { background-color: rgba(0, 0, 0, 0); ...

Align pictures in the middle of two divisions within a segment

This is the current code: HTML: <section class="sponsorSection"> <div class="sponsorImageRow"> <div class="sponsorImageColumn"> <img src="img/kvadrat_logo.png" class="sponsorpicture1"/> </div& ...

Looking to switch up the thumbs-up button design?

I am a beginner in using jquery and ajax, and I need some assistance. How can I incorporate this jquery code into my logic: $('.btn-likes').on('click', function() { $(this).toggleClass('liked'); }); Can so ...

Can the ajaxsetup error handler be used with the POST method?

I have a strange question - does the global error handler applied when using ajaxsetup get triggered in case of an Ajax error on a POST request? I've tried handling Ajax errors in several places, but the error handler is only being hit for GET reques ...

Determine the dimensions of a div element in IE after adjusting its height to auto

I am currently working on a JavaScript function that modifies the size of certain content. In order to accomplish this, I need to obtain the height of a specific div element within my content structure. Below is an example of the HTML code I am dealing wit ...

When implementing the Dropdown Picker, it is important to avoid nesting VirtualizedLists inside plain ScrollViews for optimal

Currently, I am utilizing the RN library react-native-dropdown-picker. However, when I enclose this component within a ScrollView, it triggers a warning: "VirtualizedLists should never be nested inside plain ScrollViews with the same orientation because ...

Patience is key for a fully completed JSON in JavaScript

I recently came across a similar discussion on Stack Overflow, but it involved using JQuery which I'm not using. My issue is that I need to ensure my JSON data is fully loaded before calling my function. I understand the concept of using a callback, ...

Remove Chosen Pictures (Checkbox/PHP/MySQL)

I am currently displaying images from a Database using the following HTML code: <li> <input type="checkbox" id="1" /> <a rel="gallery_group" href="images/big/1.jpg" title="Image 1"> <img src="images/small/1.jpg" alt="" ...

Using VueMultiselect with Vue 3: A guide for beginners

I'm currently experimenting with the vue multiselect component, but when I include it in the template, I am encountering a series of warnings and errors. <script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email ...

How come the gridApi.on.edit.beginCellEdit function in angular-ui-grid does not immediately refresh the dropdown options after being updated?

I am encountering a similar issue as described in this post Regarding the assignment of ui grid value drop-down box before beginCellEdit event fires in Angular However, I have noticed a slight difference. Even after updating the editDropdownOptionArray, th ...

Angular post request does not update the table

After displaying a table and a form on a page, I encountered an issue where the table does not update with new data when submitting the form. Even after refreshing the page, the new data is not reflected. As a newbie to Angular, I'm unsure of what exa ...

How can you update an image's source when hovering over it?

My goal is to switch the image source upon mouseover using a combination of asp.net and javascript. Here is the code I am currently using: <asp:ImageButton id="button" runat="server" Height="65px" ImageUrl="~/images/logo.png" OnMouseOver="src='~ ...

Calling an ajax request to view a JSON pyramid structure

My experience with ajax is limited, so I would appreciate detailed answers. I have a Pyramid application where I need to load information via ajax instead of pre-loading it due to feasibility issues. I want to retrieve the necessary information through a ...

How can I assign several Objects to a single array?

My goal is to save several objects into an array. Specifically, I have five objects named obj1, obj2, obj3, obj4, and obj5. ...