This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Changing Behavior with MapTo

2:32 RxJS lesson by

You often need streams to trigger different behaviors on the data based on which streams triggers. This lessons shows how to use mapTo to pass functions into the scan operator and have completed control over you data.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

You often need streams to trigger different behaviors on the data based on which streams triggers. This lessons shows how to use mapTo to pass functions into the scan operator and have completed control over you data.

Avatar
Sam De Boni

I made the following minor changes when working with RxJS 4.0.6:
1. use flatMapLatest in place of switchMapTo
2. use map in place of mapTo
3. assign a function to inc that returns the increment function since map evaluates its argument

const Observable = Rx.Observable;

const startButton = document.querySelector('#start');
const stopButton = document.querySelector('#stop');

const start$ = Observable.fromEvent(startButton, 'click');
const interval$ = Observable.interval(1000);
const stop$ = Observable.fromEvent(stopButton, 'click');

const intervalThatStops$ = interval$
.takeUntil(stop$);

const data = {count:0};
const inc = ()=>(acc)=>({count:acc.count+1});
const reset = (acc)=> data;

start$
.flatMapLatest(intervalThatStops$)
.map(inc)
.startWith(data)
.scan((acc,curr)=> {
return curr(acc);
})
.subscribe((x)=>console.log(x));

Avatar
nader dabit

Thanks for putting this up here, great to know!

In reply to Sam De Boni
Avatar
nader dabit

@Sam, flatMapLatest is giving me an error, "start$.flatMapLatest is not a function", on version "5.0.0-beta.6"

In reply to Sam De Boni
Avatar
Noah Rawlins

with rxjs 5.0.0 beta 7 I had to do this to get his behavior. Note the type on the mapTo. This makes sure it doesn't complain about trying to start an Observable that now emits functions with a plain object in startWith()

start$
  .switchMapTo(intervalThatStops$)
  .mapTo<any>(inc)
  .startWith(data)
  .scan((acc, curr) => curr(acc) )
  .subscribe((x) => console.log(x));
In reply to nader dabit

Right now, my stream is stuck with this one behavior in scan where it simply adds one to the count and returns a new object, but we can actually extract this out to make it more flexible and use different behaviors.

If I cut this, and we'll call it inc. I'll just say assign it to this. I can easily make this a one line of code thing. I'll delete return, delete the curlies, and one line arrow functions that only return an object need parens around them or else it will treat the curly braces as a block. Just add the parens and you're fine.

I can drop the inc in the scan, hit save, and I'll hit start, and stop, and we're good to go. Start and stop.

You can imagine if I had something like a reset behavior. We'll say reset, which instead of returning an object with a count plus one, we'll go ahead and return the original data. It will set it back to this. Then I can change this to reset, hit save, I'll hit start, and then this will just keep on logging out count zero as expected.

What we need to do to make scan flexible enough to switch between these on its own is to pass a function down the stream. If I say I want the output of my current interval to map to a function, in this case increment, I would need to tell scan that now we have an accumulator and a current and that the current value is that function and the accumulator is that original state we started with.

I hit save and now I'll hit start. It works just the same. I'll hit stop and start and stop.

Just to be clear, this interval is passing this function into scan each time as the current and then the current, which is this function here, is taking the accumulator and then returning that object just as we did before.

If I don't map to and I log this out, so I'll return just the current, you'll see now that the current is, when I hit start, just the tick going through of zero, one, two. That's coming from the interval.

We don't want that. We don't want the interval. What we want is the function, so mapto inc and then we have a function here instead of the tick, which can operate on the accumulator.

Hit save. I'll hit start. Now we're back to that original behavior.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?