Sequence

sequence() allows you to detect a specific sequence of emissions from multiple sources:
  /*!*/import { group, wrap, sequence, sink } from '@connectv/core';
import { fromEvent } from 'rxjs';

let p = document.getElementById('p');

// 'drag' is a sequence of 
// - 1 mouse down
// - one or more mouse moves ('+')
// - 1 mouse up
/*!*/let drag = sequence(1, '+', 1);

// 'click' is a sequence of
// - 1 mouse down
// - 0 mouse moves
// - 1 mouse up
/*!*/let click = sequence(1, 0, 1);

// now lets connect the 'mousedown', 'mousemove' and 'mouseup' events
// to drag and click ...
group(
  wrap(fromEvent(document, 'mousedown')),
  wrap(fromEvent(document, 'mousemove')),
  wrap(fromEvent(document, 'mouseup'))
)
/*!*/.serialTo(click, drag)
.serialTo(
  sink(() => p.textContent = 'CLICK'),    //--> click is connected to this
  sink(() => p.textContent = 'DRAG')      //--> drag is connected to this
)
.subscribe();
You can pass any number of arguments to sequence(). Each argument corresponds to an incoming event, and has an input pin (named numerically). Each argument must be one of the following: The sequence() will then match sequences of incoming emissions to the described sequence, and emit the matching sequences. So in the example above:
let drag = sequence(1, '+', 1);
drag will emit only when it receives exactly one emission on its first input drag.in(0), then at least one emission on its second input drag.in(1), and then exactly one emission on its third input drag.in(2).

Here is another example to play around with:
  /*!*/import { wrap, sequence, pipe, sink } from '@connectv/core';
import { fromEvent } from 'rxjs';
import { delay } from 'rxjs/operators';

let A = document.getElementById('A');
let B = document.getElementById('B');
let C = document.getElementById('C');
let D = document.getElementById('D');
let p = document.getElementById('p');

// so the desired sequence of actions is:
// - 1 or more clicks on A
// - no clicks on B
// - any number of clicks on C (maybe 0 even)
// - 2 clicks on D
/*!*/let seq = sequence('+', 0, '*', 2);
wrap(fromEvent(A, 'click')).to(seq.in(0));
wrap(fromEvent(B, 'click')).to(seq.in(1));
wrap(fromEvent(C, 'click')).to(seq.in(2));
wrap(fromEvent(D, 'click')).to(seq.in(3));

seq.output.to(sink(() => p.textContent = 'SEQUENCE!'))
  .to(pipe(delay(2000)))
  .subscribe(() => p.textContent = '');
Note that in this example we have plugged the sequence() into our flow explicitly (by mentioning all of its input and output pins explicitly). However, as evident from the first example, sequence() also supports
implicit connections:
/*!*/import { group, wrap, sequence, pipe, sink } from '@connectv/core';
import { fromEvent } from 'rxjs';
import { delay } from 'rxjs/operators';

let A = document.getElementById('A');
let B = document.getElementById('B');
let C = document.getElementById('C');
let D = document.getElementById('D');
let p = document.getElementById('p');

group(
  wrap(fromEvent(A, 'click')),
  wrap(fromEvent(B, 'click')),
  wrap(fromEvent(C, 'click')),
  wrap(fromEvent(D, 'click')),
)
/*!*/.serialTo(sequence('+', 0, '*', 2))
.to(sink(() => p.textContent = 'SEQUENCE!'))
.to(pipe(delay(2000)))
.subscribe(() => p.textContent = '');

Signature

Each sequence() has the same number of inputs as arguments provided to it (i.e. the length of the described sequence). These inputs are named numerically, i.e. seq.in(0), seq.in(1), ....

The output of the sequence is accessible either via seq.out("out"), or the shortcut property .output.

Further reading




Copied to Clipboard!