This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Managing State in RxJS with StartWith and Scan

2:23 Angular 2 lesson by

The scan operator in RxJS is the main key to managing values and states in your stream. Scan behaves just as a reduce function would, but scan is able to collect values from streams over time. This lesson covers using startWith to set the initial accumulator value then using scan to update the value of the clock from the clicks and interval.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

The scan operator in RxJS is the main key to managing values and states in your stream. Scan behaves just as a reduce function would, but scan is able to collect values from streams over time. This lesson covers using startWith to set the initial accumulator value then using scan to update the value of the clock from the clicks and interval.

Avatar
Randy

I had an issue with the accumulator.

const date = new Date(acc.getTime());
When transpiling, I got a typescript error:

Property 'getTime' does not exist on type '{}'.

While searching online I found some people having the same issue with not declaring a type.
I solved it by creating a new variable with type 'any' and assigned the value of the acc (accumulator) to it.
let acc2:any= acc;
const date = new Date(acc2.getTime());

I have a feeling that this isn't the best solution but I couldn't figure how to get the correct type to apply to acc2.

In reply to egghead.io
Avatar
Goma Games

i got it to work by setting the type of acc to Date
without setting the type, i get this compile time error

Operator '+' cannot be applied to types 'Object' and 'number'.
export class ClockComponent {
  public click$ = new Subject();
  public clock:Observable<Date>;

  constructor(){
    this.clock = Observable
    .merge(
      this.click$,
      Observable.interval(5000)
    )
    .startWith(new Date())
    .scan((acc:Date, curr)=> new Date(acc.getTime()+1000) );
  }

}

hth

In reply to Randy
Avatar
Fabio Biondi

Here my quick fix to the example:

.startWith(new Date().toString())

and

.scan((acc, action) => {
     let date = new Date(acc);
     switch (action) {
        case 'xyz':
           date.setSeconds(date.getSeconds() + 1);
           ...
     }
     return date;
Avatar
Anzumana

great solution. thanks

In reply to Goma Games

Since I want to control the clock, like move the time forward or backward or whatever, right now I'm just pushing a new date every five seconds or every time I click. What I need to do is actually track a date and then make changes to that date.

When you think I need to track something in RxJS, think, I want to start with an initial value. That's the initial value is a new date. Every time some event comes through, I'm going to check for it and then change it. That new date is this accumulator, and then I can use the current, the thing that comes through, to change the accumulator however I want.

To start with, I'm just going to return the accumulator to see what happens, and I need to go ahead and import start with, and import scan. Hit Save, refresh.

You can see that it's going to give us one value, and no matter what I do, it's just going to return that same value. The clock is no longer updating, it's just set to that initial value. Every time, it's returning that same accumulated value.

To be able to update this, I need to say that when something comes through, I want to grab a copy. We'll say date is, a new date. We'll just grab the accumulator, get the time, and then return that date.

Since we have a copy of it, it's going to behave the exact same way, since it's just returning that copy. But what we can do is take that date and change it. I'll say date, set seconds, date, get seconds, and then add one.

When I save and I refresh, you can see it starts with that initial date, and then every five seconds, it's going to update. It'll hit five and that updated to one second. When I click, it's going to move that forward and then five seconds, it pushed another value in here.

I'll change this to one second so it looks more natural, refresh. You can see that every second, this is going to update. But I can also make it update even faster by clicking the button.

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