Recognizing and exact series of events in RxJS

风格不统一 提交于 2019-12-23 01:45:41

问题


Using RxJS, I want to fire an event if the user types 'a' then 'b' then 'c'.

I do not want the event fired if they enter 'a' then 'b' then 'z' then 'c'.

Here is my codepen of the work I have done so far (in TypeScript).

class App1 {
    private divStream: HTMLElement;
    private divResult: HTMLElement;

    constructor(divStream: HTMLElement, divResult: HTMLElement) {
            this.divStream = divStream;
            this.divResult = divResult;
    }

    start() {
        var filterByCharacter = (expectedCharater) => {
            return (char) => { return char === expectedCharater; };
        };

        var values = ['a', 'b', 'b', 'c', 'b'];

        var obChars = Rx.Observable.fromArray(values);
        obChars.subscribe((k) => {
            divStream.innerHTML += "<div style='color: blue'>" + ":: " + k + " ::" + "</div>";
                },
            (err) => {
                divStream.innerHTML += "<div style='background-color: blue' > " + 'Error: ' + err + " </div>";
            },
            () => {
                divStream.innerHTML += "<div style='background-color: blue'>" + ":: finished ::" + "</div>";
            }
        );

        function log(text: string) {
            divResult.innerHTML += "<div style='color: green'>" + text + "</div>";
        }
        var obA: Rx.Observable<string> = obChars.filter(filterByCharacter('a'));
        var obB: Rx.Observable<string> = obChars.filter(filterByCharacter('b'));
        var obC: Rx.Observable<string> = obChars.filter(filterByCharacter('c'));

        let aSteps: Rx.Observable<any>[] = [];
        aSteps.push(obA.take(1).do(() => { log("a"); }).ignoreElements());
        aSteps.push(obB.take(1).do(() => { log("b"); }).ignoreElements());
        aSteps.push(obC.take(1).do(() => { log("c"); }));
        let steps: Rx.Observable<any> = Rx.Observable.concat<any>(aSteps);
        var source = steps
            .takeUntil(Rx.Observable.timer(100 * values.length));

              var subscription = source.subscribe(
            function (x) {
                log("Next: " + x);
            },
            function (err) {
                divResult.innerHTML += "<div style='background-color: green'>Error: " + err + "</div>";
            },
            function () {
                divResult.innerHTML += "<div style='background-color: green' > " + 'Completed' + "</div>";
            });
    }

    stop() {
        clearTimeout(this.timerToken);
    }

}

window.onload = () => {
    var app = new App1(document.getElementById('divStream'), document.getElementById('divResult'));
    app.start();
};

回答1:


This seems to be working, it uses a simple state machine and is generalizable to recognize any basic regular expression. The regular expression recognized here is *abc* :

function noop () {}

var keyUp$ = 
  Rx.Observable.fromEvent(ta_input, 'keyup')
               .map(function(ev){return ev.keyCode});

var stateMachine$ = keyUp$
  .scan(function (state, keyCode) {
    if (String.fromCharCode(keyCode) === state.password[state.index]) {
      state.index++;
      if (state.index === state.password.length) {
        state.found = true;
      }
    } 
    else {
      state.index = 0;
      state.found = false;
    }
    return state;
}, {password : 'ABC', index : 0, found: false})
  .filter(function (state){return state.found})
  .take(1)

stateMachine$.subscribe(noop)

To check it, run the jsffidle, and type abc in the textarea. For some reason, your password has to be in caps, but that part should be easy to fix. When the abc substring is detected, the stateMachine$ observable emits found and completes.




回答2:


I believe you are looking for bufferWithCount.

Check out this spec from RxJSNext (renamed bufferCount in next):

it('should emit full buffer then last partial buffer if source completes', function () {
  var e1 =   hot('--a^-b--c--d--e--|');
  var e1subs =      '^             !';
  var expected =    '--------y-----(z|)';

  expectObservable(e1.bufferCount(3)).toBe(expected, {
                                             y: ['b', 'c', 'd'],
                                             z: ['e']
                                           });
  expectSubscriptions(e1.subscriptions).toBe(e1subs);
 });


来源:https://stackoverflow.com/questions/34890358/recognizing-and-exact-series-of-events-in-rxjs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!