Utilizing rxjs for creating behavior similar to a Register

As a beginner in rxjs and declarative programming, please forgive me if this question seems naive!

I am working with Typescript, attempting to create functionality similar to that of a digital register. I have two input boolean observables, A and B, as well as an output register O (also boolean).

Specifications:

  1. O should initially be set to "false"
  2. When B transitions from FALSE to TRUE, O should be updated with the current value of A
  3. In all other cases, the current value of O should remain unchanged

My goal is to store the value of A when B becomes true, so that I can use it when B goes false again.

I came across this question, but I'm struggling to apply its answer to my specific scenario.

I believe I can utilize pairwise() on B to detect the transition from FALSE to TRUE (previousValue === false && currentValue === true), along with withLatestFrom to access the current value of A and update O accordingly.

However, I'm unsure how to retain/re-emit the current value of O in all other situations. It appears that there is no way, within a pipe operator defining Observable O, to reference its existing value.

Answer №1

To meet your requirements quickly, I have developed the following solution:

  1. Initialize observables a$ and b$ as BehaviorSubject and ReplaySubject respectively.
    • a$: BehaviorSubject<string>
      : Emits either a default value or the last emitted value to subscribers (using a$.next()). If you need different behavior, you can change it by using ReplaySubject with buffer size 1 (emits the last value without a default) or Subject (does not transmit previous emissions to future subscribers).
    • b$: ReplaySubject<boolean>(1)
      : Transmits the most recent emitted value to future subscribers.
  2. Define an Observable bTransformer$ that fulfills your requirements with the following operators:
    • distinctUntilChanged - emits only when values of b$ change, e.g., from true to false or vice versa.
    • pairwise - emits previous and current values as an array, such as [true, false] or [false, true].
    • combineLatestWith(a$) - combines with the value of a$, for example, [[true, false], 'value of a'].
    • filter - emits only when b$ changes from false to true.
    • map - transmits the value of a$.
  3. Create the output observable o$ - initialized with false using the startWith operator and emitting whenever bTransformer$ does.

Keep in mind that with the current setup, o$ will also emit each time a value is transmitted to a$ due to wiring it using the combineLatestWith$ operator.

Feel free to test the code snippet below:

// JavaScript code goes here

// Instantiate necessary RxJS elements
const { BehaviorSubject, ReplaySubject, combineLatestWith, distinctUntilChanged, pairwise, filter, startWith, map } = rxjs;

// Initialize Behavior Subject for 'a' and Replay Subject for 'b'
const a$ = new BehaviorSubject('value of a');
const b$ = new ReplaySubject(1);

// Create Transformation Observable 'bTransformer$'
const bTransformer$ = b$.pipe(
  distinctUntilChanged(),                
  pairwise(),                            
  combineLatestWith(a$),                 
  filter(([[bValueOld]]) => !bValueOld),
  map(([_, a]) => a)
);

// Setup Output Observable 'o$'
const o$ = bTransformer$.pipe(
  startWith(false)
);

// Functions to handle button clicks
function onClickB(value) {
  b$.next(value);
}

function emitValueA() {
  const value = document.getElementById('a-input').value;
  a$.next(value);
}

// Subscribe to 'o$'
o$.subscribe(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.8.1/rxjs.umd.min.js"></script>

// HTML buttons and input field for testing
<button onclick="onClickB(true)">Emit true to b</button>
<button onclick="onClickB(false)">Emit false to b</button>
<br>
<br>
<input id="a-input"/>
<button onclick="emitValueA()">Emit value to a</button>

Answer №2

Simplifying the process with a single stream and a register state variable.


Starting off by creating checkboxes to track actions A and B, and displaying output C.

A: <input type="checkbox" id="A" /><br />
B: <input type="checkbox" id="B" /><br />
<div id="C">false</div>

Fetching the elements using javascript.

const a: any = document.getElementById('A') as HTMLElement;
const b: HTMLElement = document.getElementById('B') as HTMLElement;
const c: HTMLElement = document.getElementById('C') as HTMLElement;

Using fromEvent and map, we listen for checkbox clicks and extract the checked property from the event using map.

const checkboxStream = (element: any) => {
  return fromEvent(element, 'input').pipe(
    map((event: any) => event?.target?.checked)
  );
};

Next step is listening for the input event and subscribing to events from B, as it triggers storing the checkbox value.

With a simple if condition, the register state (registerState) gets updated when b is true, otherwise it retains the current state.

let registerState = a.checked;
checkboxStream(b)
  .pipe(
    map((bChecked: Array<boolean>) => {
      if (bChecked) {
        registerState = a.checked;
      }
      return registerState;
    })
  )
  .subscribe((cChecked: boolean) => {
    c.innerText = cChecked.toString();
    console.log(cChecked);
  });

Check out the Stackblitz Demo

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

Encountering an error when using Webpack ModuleFederationPlugin and HMR: "Undefined properties cannot be set"

Description Hey everyone! I've been experimenting with Webpack ModuleFederationPlugin using React and TypeScript in my current proof of concept. Currently, I have two applications - ChildApp which exposes a module, and a HostApp that consumes this e ...

Seeking assistance with producing results

Is there someone who can provide an answer? What will be the output of the code snippet below when logged to the console and why? (function(){ var a = b = 3; })(); console.log("Is 'a' defined? " + (typeof a !== 'u ...

Tips for creating a tailored Express.js request interface using Typescript efficiently

I have been working on designing a custom Express request interface for my API. To achieve this, I created a custom interface named AuthRequest, which extends Request from Express. However, when attempting to import my interface and define req to utilize t ...

Angular2 error: "missing exported member 'bootstrap'"

Upon opening my Atom editor, I encountered the following message: The issue of 'Module '"C:/express4/node_modules/@angular/platform-browser-dynamic/index"' not exporting member 'bootstrap' raised at line 2 col 10 This warning a ...

Working with Vue.js and Axios: Extracting data from a nested Axios response

I am currently working on a project that involves Vue.js, TypeScript, and Axios. My main focus is on creating a complex ApiRequest. Unlike the traditional method of fetching data using axios directly in the component, I wanted to find a more maintainable s ...

Having trouble with VueJS ref not preventing the default form action on submit?

Within my <script> tag, I currently have the following code: render(createElement) { return createElement("form", {ref: "formEl" , on: {submit: this.handleSubmit} }, [ <insert create form inputs here> ]); } handleSubmit(e) { ...

Creating generic output types in TypeScript based on the input types

In my React-Native project, I'm focusing on implementing autocomplete and type validation. One of the challenges I'm facing is configuring the types for the stylesheet library I am using. A customized stylesheet is structured like this: const s ...

Creating mock objects with Jest

I am currently delving into the world of jest testing. Here is a snippet from an implementation class I'm working with: import { ExternalObject } from 'external-library'; export class MyClass { public createInstance(settings : ISettings) ...

Is it possible to enable full screen window functionality in Angular 2 by simply clicking a button? Let's find out

After successfully creating the user login page, I am facing an issue. When the submit button is clicked, the page should navigate to a specific component (test.component.ts and test.component.html). My goal now is to make that window go into full screen m ...

What is the best way to utilize the features of component A within component B when they exist as separate entities

Component A has all the necessary functionalities, and I want to use it in Component B. The code for ComponentA.ts is extensive, but it's not written in a service. How can I utilize the logic from Component A without using a service, considering both ...

Angular does not propagate validation to custom form control ng-select

In my Angular 9 application, I am utilizing Reactive Forms with a Custom Form Control. I have enclosed my ng-select control within the Custom Form Control. However, I am facing an issue with validation. Even though I have set the formControl to be requir ...

The most effective approach to creating linked observable subscriptions

How can we refactor this code reactively using RxJS for better performance? let profileInformation; updateProfile() { let token; let profileId = 1; this.userService.getAccessToken() .pipe( tap((res) => { //as I need it multipl ...

Guide to removing selected value from a combobox in Angular

I am working on a simple HTML file that consists of one combobox and one clear button. I want the clear button to remove the selected value from the combobox when clicked. Below is my code: mat-card-content fxLayout="row wrap" fxLayoutAlign="left" fxLayou ...

Passing an array of objects as properties in React components

My functional component looks like this: function ItemList({ items }: ItemProps[]) { return <p>items[0].name</p> } Here is how I'm creating it: <ItemList items={items} /> The array items contains objects in the format [{name: &ap ...

What is the best way to employ TypeScript for passing parameters to JavaScript functions that utilize the arguments object?

Using Angular 8 at the moment and attempting to implement a script from someone else. However, I am facing an issue due to my lack of knowledge in this area. The function in the javascript operates like this: window.X = function() { var e = argument.l ...

Displaying svg files conditionally in a react native application

I have developed an app specifically for trading dogs. Each dog breed in my app is associated with its own unique svg file, which are all stored in the assets folder (approximately 150 svg files in total). When retrieving post data from the backend, I re ...

What causes the form to consistently show as invalid once it has been submitted?

register.html : <form [formGroup]="signupForm" (submit)="onSubmit()" class="form-detail"> <h2>Registration Form</h2> <div class="form-row-total"> <div class="form-row"> <in ...

Sinon - observing a spy that remains inactive, yet the test proceeds to enter the function

Having some trouble with a test function that uses two stubs. The stubs seem to be working fine, as I can see the spy objects inside when I console.log res.json or next. However, the spy is not being called when I make the assertion. The error message read ...

Utilizing ES6, accessing the first element of an array of objects

How can I access the values of the first or a specific object in an array based on an index using ES6? arrayOne =[ { child: [ {e1: 'ABCD', e2: 'BCDF'}, {e1: '1234', e2: '5689'}, {e1: 'QAZ ...

The functionality of Angular 6 Material Nested Tree is disrupted when attempting to use dynamic data

In Angular 6, I am utilizing mat-tree along with mat-nested-tree-node. My objective is to dynamically load the data when the user toggles the expand icon. Attempting to apply the dynamic data concept from the Flat Tree example provided in Material Example ...