Home > database >  RXJS way to unsubscribe after button click but with opportunity to subscribe again
RXJS way to unsubscribe after button click but with opportunity to subscribe again

Time:11-13

import { reduce, filter, map, mapTo } from 'rxjs/operators'
import { from, fromEvent, scan, Subscription } from 'rxjs'

const button1 = document.getElementById("but1")
const button2 = document.getElementById("but2")
const button3 = document.getElementById("but3")



let click1 = fromEvent(button1, 'click')
.subscribe(result => {
    count3.subscribe(x => p3.innerHTML = `Click count: ${x}`)
})


let click2 = fromEvent(button2, 'click')

here i want to unsubscribe subscription (when i click on second button, but with opportunity to subscribe again when i click first button)

I've tried with something like this

const sub = click1.subscribe(result => {
        count3.subscribe(x => p3.innerHTML = `Click count: ${x}`)
    })


let click2 = fromEvent(button2, 'click')
    sub.unsubscribe()

But I don't know how to put sub.unsubscribe() into button

let click3 = fromEvent(button3, 'click')

let three = click3.pipe(mapTo(1))

let c: number = 0

let count3 = three.pipe(scan((acc, val) => acc   val, c))

const d = document.getElementById("d")
const p3 = document.createElement("p")


//count3.subscribe(x => p3.innerHTML = `Click count: ${x}`)

d?.appendChild(p3)

CodePudding user response:

We can unsubscribe the subscription on the second button click and then when the first button is clicked again, we need clear any subscribes already present, then we reinitialize the subscribtion, finally we subcribe again.

Please let me know if you find this confusion, I will clarify your doubts.

Am not sure what you are trying to achieve, but please use the below example and modify it to your use case.

import { mapTo } from 'rxjs/operators';
import { fromEvent, scan, Subscription } from 'rxjs';

const button1 = document.getElementById('but1');
const button2 = document.getElementById('but2');
const button3 = document.getElementById('but3');
let clickCountSubscription = new Subscription();
let interimValue = 0;
const getCount3 = () => {
  let click3 = fromEvent(button3, 'click');
  let three = click3.pipe(mapTo(1));
  return three.pipe(
    scan((acc, val) => {
      interimValue = acc   val;
      return acc   val;
    }, interimValue)
  );
};
let click1 = fromEvent(button1, 'click').subscribe((result) => {
  clickCountSubscription.unsubscribe();
  clickCountSubscription = new Subscription();
  clickCountSubscription.add(
    getCount3().subscribe((x) => (p3.innerHTML = `Click count: ${x}`))
  );
});

let click2 = fromEvent(button2, 'click').subscribe(() => {
  clickCountSubscription.unsubscribe();
});
const d = document.getElementById('d');
const p3 = document.createElement('p');

d?.appendChild(p3);

stackblitz

CodePudding user response:

Note: This answer is based on the dialog in the comments of the main question. Taking the question literally this is a worse solution than Narem Murali's

To do this in a more reactive way you can compose several streams together using only one subscribe. This will make manage the subscription simpler and help with nesting, but will involve more stream logic and rxjs operators.

import { map, fromEvent } from 'rxjs';
import { filter, mergeWith, withLatestFrom } from 'rxjs/operators';

// Get the buttons
const startBtn = document.getElementById('start');
const stopBtn = document.getElementById('stop');
const countBtn = document.getElementById('count');

// Setup base input streams (could be done later separated here for clarity)
const start$ = fromEvent(startBtn, 'click').pipe(map(() => true));
const stop$ = fromEvent(stopBtn, 'click').pipe(map(() => false));

// Merge base input streams so that you only get one output
const shouldTake$ = start$.pipe(mergeWith(stop$));

const count$ = fromEvent(countBtn, 'click').pipe(
  // listen for the count click
  withLatestFrom(shouldTake$), // determine what the latest value from the merged stream
  map(([_, shouldTake]) => shouldTake), // ignore the actual click event and just use shouldTake
  filter((shouldTake) => shouldTake) // Stop the emission if you shouldn't take it
);

// Get the counter span
const counterSpan = document.getElementById('current-count');

let count = 0;

// Actually subscribe to count and do what you care about when you care
count$.subscribe(() => {
  count  ;
  counterSpan.innerText = count.toString(10);
});

To see this at work check out this stackblitz https://stackblitz.com/edit/rxjs-zcbaxz?file=index.ts

  • Related