1
/**
 * Created by darius on 02/04/16.
 */
import { Component } from 'angular2/core';
import { Observable } from 'rxjs/Rx';


@Component({
  styles: [ require('../../style.css') ],
  selector: 'keypresses-per-second',

  template: `

    <div class="block">

      <input  type="text" (keypress)="onKeypress($event)">

      {{keypresses}} <br>
      <input type="text" (keypress)="onKeypressReact($event)">
      {{keypressesReactive}}
    </div>
  `
})

export class KeypressesPerSecond {

  ngOnInit() {

    this.nonReactive();

    this.reactiveWay();
  }

  // not reactive
  keypresses = '';
  counter = 0;
  secondsPassed = 0;

  nonReactive(){

    var self = this;

    var int = setInterval(function(){

      console.log(self.counter, 'counter in non reactive')
      self.keypresses += self.counter + ', ';
      self.counter = 0;
      self.secondsPassed++
      if (self.secondsPassed > 30) {
        clearInterval(int);
      }
    }, 1000);
  }

  onKeypress($event){
    console.log($event.keyCode);
    this.counter++;
  }
  // end not reactive

  onKeypressReact() {}

  keypressesReactive = '';
  reactiveCount = 0;

  reactiveWay() {

    console.log('reactive way')

    const keypressObservable$ = Observable.create(observer => {

      // from template
      this.onKeypressReact = () => { observer.next('press'); };
    });


    keypressObservable$.subscribe(function(event) {
      self.reactiveCount++;
    });

    var self = this;

    var timer$ = Observable.create(function(observer){

      // is subscribed to this observable
      var subscribed = true;
      var int = setInterval(function() {

        if (subscribed) {
          observer.next(self.reactiveCount);
          self.reactiveCount = 0;
        }

        if (self.secondsPassed > 30) {
          observer.complete();
          clearInterval(int)
        }

      }, 1000);

    })


    timer$.subscribe(
      function (x) {
        console.log('Nextzz: %s', x);
        self.keypressesReactive += x + ', ';
      });

  }

}

I tried to write reactive and non reactive way of keypresses counter. Take a look at function reactiveWay()

it works, but I think there might be something wrong.

I done excersizes in there http://reactivex.io/learnrx/

and there was lot of mapping.

It feels like I I had to map the time event to sequence of key events happened per second. But do not get how could I map those.

Something like

// doing this way we could removed some code from timer$, we just need to get an event
var kps$ = timer$.concatMap(function(time) {

  var sum = keypressObservable$.takeUntil(timer$)
    .reduce(function (acc, cur) {
      return acc + cur;
    })

  console.log('sum', sum);

  return sum;
})

// this works, counts the keypresses, but only when pressing at least 1. 
kps$.subscribe(
  function (x) {
    console.log('kps next', x);
    self.keypressesReactive += x + ', ';
  });

How do I force kps$ to emit 0 sum when no keypresses done in the second if I use the kps$?

Update

Based on the answer, I have done this.

var source = Observable.fromEvent(document.body, 'keypress');

var delayedSource = source.delay(1000);


var obs = source

  .buffer(delayedSource)


  .map((clickBuffer) => {
    return clickBuffer.length;
  })

But when I subscribe to the obs, I do not get event each second containing 0 value still. When I press some keys in a second, then I get the number of keys pressed and another event of 0. And then events stop until I press keys again. What do I need to modify so I get event each second?

Dariux
  • 3,953
  • 9
  • 43
  • 69

1 Answers1

3

I think that you could leverage the buffer operator. It allows to buffer events and sends them after an amount of time. You could then map this list of events to its length.

var source = Observable.fromEvent(document.body, 'keyup');

var obs = source
     .bufferTime(1000).map((clickBuffer) => {
       return clickBuffer.length;
     });

obs.subscribe((num) => {
  // Get the number of pressed keys per second
});

See these links:

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Does not work for me, at least in RxJs 5 - getting error: Error:(161, 15) TS2345: Argument of type '() => Observable<{}>' is not assignable to parameter of type 'Observable'. Property '_isScalar' is missing in type '() => Observable<{}>'. – Dariux Apr 03 '16 at 06:18
  • Found out how to fix the error - passed delayedSource to the buffer fucntion. But still it does not work like I want – Dariux Apr 03 '16 at 08:28
  • 1
    You're right. You should use the bufferTime operator. I updated my answer accordingly... – Thierry Templier Apr 03 '16 at 08:30