Exploring the power of combining observables in RxJS

Having difficulty combining observables in my implementation of a tags-input feature.

this._allTags represent all available tags.

I am working with 4 streams:

  this._suggestions = new this.rx.Subject;
  this._searchText = new this.rx.Subject;
  this._selectedIndex = new this.rx.Subject;
  this._eventsStream = new this.rx.Subject; 

For the search method:

search(searchText) {
  this._searchText.onNext(searchText);
  this._selectedIndex.onNext(-1);
}

When it comes to the KeyDown method:

keyDown(event) {
  this._eventsStream.onNext(event);
}

Here is the logic behind searching:

  const partitionSearchText = this._searchText
    .partition((searchText) => !!searchText); //checking if searchText is not empty

  partitionSearchText[0]
    .subscribe((searchText) => this._suggestions.onNext(
        this._allTags.filter((item) => ~item.name.toLowerCase().indexOf(searchText.toLowerCase()))
      ));

  partitionSearchText[1]
    .subscribe((searchText) => this._suggestions.onNext([]));

My goal now is to implement events. When there is a searchText and a keyDown event, I want to increment this._selectedIndex, but if this._selectedIndex reaches the length of this._suggestions, then I need it to stop incrementing.

This is what I currently have:

  const eventsWithSearchText = this._searchText
    .map((searchText) => !!searchText ? this._eventsStream : this.rx.Observable.empty())
    .switch()

  const keyDownEvents = eventsWithSearchText
    .filter((event) => event.keyCode === DOWN_KEY)

  keyDownEvents
    .subscribe((event) => event.preventDefault())

  const isNotLast = this._selectedIndex
    .combineLatest(this._suggestions, (index, sugg) => index !== sugg.length - 1);

  keyDownEvents
    .subscribe((item) => {
      this._selectedIndexValue++
      this._selectedIndex.onNext(this._selectedIndexValue);
    });

Although it increments this._selectedIndex, it does not stop when reaching the same length as this._suggestions.

Any help would be greatly appreciated!

Visit the link for more details.

Answer №1

Success! Check out the following code:

  const eventsWithSearchText = this._searchText
    .map((searchText) => !!searchText ? this._eventsStream : this.rx.Observable.empty())
    .switch()

  const keyDownEvents = eventsWithSearchText
    .filter((event) => event.keyCode === DOWN_KEY)

  keyDownEvents
    .subscribe((event) => event.preventDefault())

  const keyUpEvents = eventsWithSearchText
    .filter((event) => event.keyCode === UP_KEY)

  keyUpEvents
    .subscribe((event) => event.preventDefault())

  const enterEvents = eventsWithSearchText
    .filter((event) => event.keyCode === ENTER_KEY)

  enterEvents
    .subscribe((event) => event.preventDefault())

  const isNotLast = this._selectedIndex
    .combineLatest(this._suggestions, (index, sugg) => index !== sugg.length - 1);

  const keyDownAndNotLast = keyDownEvents
    .map(() => +1)
    .withLatestFrom(isNotLast, (value, notLast) => notLast ? value : false)
    .filter((item) => item)

  const keyUpEventsAndNotFirst = keyUpEvents
    .map(() => -1)
    .withLatestFrom(this._selectedIndex, (value, index) => !!index ? value : false)
    .filter((item) => item)

  this.rx.Observable.merge(
    keyDownAndNotLast,
    keyUpEventsAndNotFirst,
    enterEvents
      .map(() => ({reset: true}))
    )
    .scan((acc, value) => value.reset ? -1 : acc + value, -1)
    .subscribe((item) => {
      this._selectedIndex.onNext(item);
    });

https://plnkr.co/edit/soaChC?p=preview

I hope someone finds this useful.

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

Material-UI: The call stack has exceeded the maximum range, causing an Uncaught RangeError

I am currently utilizing the Dialog and Select components offered by Material-UI in conjunction with React. Here is a quick example: import React from 'react'; import { Dialog, MenuItem, Select } from '@material-ui/core'; class Examp ...

The Ajax Control Upload consistently defaults to the default value and disregards any text input selected from the drop-down list

On my website, I have implemented an ajax control upload event that allows users to upload a zip file and then unzip it using zlib. The folder name for unzipping is created based on the selection from a dropdown list. However, I am facing some issues where ...

Unraveling Angular: Generating a Random Sequence of Symbols from an Array Multiple Times

A collection of symbols from A to E is at my disposal. My task is to display each symbol using ng-repeat, but the order in which they appear should be random and each symbol needs to be repeated n times (let's say 4). ...

Pop-up website opening with fixed dimensions error

On my webpage, I have a terminal where you can type commands and receive output. For example, typing "/unsolvedproblems" displays a list of unsolved problems with a hyperlink. I've been trying to make the hyperlink open in a popup window with a fixed ...

Generating various API calls and delivering them to a template (Express + Node.js + Facebook open graph)

I am currently developing a unique Express Node.js application that utilizes the extraordinary capabilities of this remarkable Facebook SDK. Allow me to present my existing route for the root: app.get('/', Facebook.loginRequired(), function (req ...

Struggling to send data to Wufoo API using PHP and AJAX

I'm still getting the hang of PHP and attempting to send data to a Wufoo Form that includes the fields shown below: https://i.sstatic.net/yoOgy.png However, when trying to POST information to it, I keep receiving a 500: Internal Server Error along w ...

The search box output will be the same as the JSON result

I have a server in Node.js that is able to read and process a JSON file containing various data, including unique user IDs. I have incorporated a search box into my HTML page, and I am seeking assistance with creating a jQuery method (which will require AJ ...

Guide on Combine Multiple Observables/Subscriptions into a Nest

1. A Puzzle to Solve I am faced with the challenge of implementing a dynamic language change flow for my blog. Here is an overview of how I envision it: The user initiates a language change by clicking a button that triggers an event (Subject). This eve ...

Displaying a component after retrieving a value from AsyncStorage in a React Native application

I have developed a React Component that saves user settings in the AsyncStorage and retrieves them upon loading. The functionality of storing and retrieving data is working fine, but I am facing an issue where the component renders before the values are ...

Preventing Prepend Scroll: Tips and Tricks

Adding extra content to the top of the body can be frustrating, especially if it pushes everything down as you're trying to read. Is there a way to smoothly prepend this additional content without shifting the page layout, so that it seamlessly appear ...

Mastering React: Implementing default values in components using Ajax

I am facing an issue while trying to create a form for editing existing values. The problem arises with the initial data retrieved from an ajax request, causing my component to render twice - first with empty values and then again when the data is populate ...

Ways to activate flashlight on mobile using React.Js

Is it possible to control the torch light of a mobile device by toggling a button? https://i.stack.imgur.com/x9nIf.png <IconButton onClick={() => setFlashOn(!flashOn)} style={{ position: "absolute", right: 80, top: 20, zIndex: ...

What is the best method to determine the accurate height of a window that works across all browsers and platforms?

Is there a way to accurately determine the visible height of the browser window, taking into consideration any floating navigation bars or bottom buttons that may interfere with the actual viewing area? For example, mobile browsers often have floating bar ...

Can a variable be declared within the path references of the Firebase database?

In an effort to update my app's database references, I am working on implementing specific Firebase rules that involve adding buildings and depts nodes inside the user node. This decision was prompted by a discussion on best practices for writing Fire ...

Displaying the Selected Value from the DropDown in the Menu

I am working with Bootstrap5 and have the following dropdown menu in my code. Instead of displaying "Year," I would like to show which member was selected. How can I achieve this? <div class="dropdown"> <button class="btn btn- ...

Prevent the display of list elements upon clicking by utilizing Angular's Observable and async features

My search bar allows users to enter characters, and through Angular Observable with HTTP GET, they receive suggestions for similar keywords. When a user clicks on a suggestion, it populates the search form with that keyword. The issue is that even after s ...

The Vue.js @click event does not function properly when used in a selection on mobile

I designed a dropdown menu with different options, and when one is selected it updates the "Value" in vue to a specific amount. Then, I display the selected amount in an input field. For example: <select class="form-control" style="max-width: 150px;" ...

JS: I'm struggling to understand the scope

I've been working on adapting CouchDB's JS API to function asynchronously, but I'm encountering an unresolved error: You can find my version of the JS API here on Pastebin. Whenever I execute (new CouchDB("dbname")).allDocs(function(result) ...

What are some strategies for safeguarding a disabled button?

Is there a way to securely disable a button if the user does not have permission to access it? I currently disable it at the Page_Load event: Page_Load() { if(!userhasrights) { btn.Enabled=false; } } However, after rendering, ASP.N ...

Anomalous Snackbar and Alert Interactions

Why am I getting an error with this code snippet: import Snackbar from "@mui/material/Snackbar"; import MuiAlert from "@mui/material/Alert"; const Alert = ({children}) => <MuiAlert>{children}</MuiAlert> <Snackbar ope ...