问:RXJS:"链接"输入框值。

时间:2017-11-23 09:48:43

标签: javascript rxjs reactive-programming

我有一个带有x输入框的UI。我希望框中的值从左到右增加1。此插件中的功能如下:https://plnkr.co/edit/82sNDb?p=preview

const inputValue = element =>
  Rx.Observable.fromEvent(element, 'input').map(e => 
    parseInt(e.target.value, 10));

const box1$ = inputValue(box1);
const box2$ = inputValue(box2);
const box3$ = inputValue(box3);

box1$.subscribe((val) => {
  box2.value = val + 1;
  box3.value = val + 2;
});

box2$.subscribe((val) => {
  box1.value = val - 1;
  box3.value = val + 1;
});

box3$.subscribe((val) => {
  box1.value = val - 2;
  box2.value = val - 1;
});

尝试扩展它以获得更多的盒子似乎很难,所以我尝试将它们链接在一起;其中一个框中的更改传播到' next'框。 我似乎无法以一种非复杂的方式做到这一点,并且使用主题将值推送到流。有更清洁的方法吗?

我的链式实施:https://plnkr.co/edit/tbM5Gh?p=preview

window.addEventListener('DOMContentLoaded', () => {
 const box1 = document.querySelector('#box1');
 const box2 = document.querySelector('#box2');
 const box3 = document.querySelector('#box3');

 const box1Subject = new Rx.Subject();
 const box2Subject = new Rx.Subject();
 const box3Subject = new Rx.Subject();

 // link box1 -> box2
 const box1$ = createBoxStream(box1)(box1Subject)(val => val + 1)
   .subscribe((newValue) => {
   box2.value = newValue;
   box2Subject.next(newValue);
  });

// link box2 -> box3
const box2$ = createBoxStream(box2)(box2Subject)(val => val + 1)
 .subscribe((newValue) => {
   box3.value = newValue;
   box3Subject.next(newValue);
 });

// link box3 -> box1
const box3$ = createBoxStream(box3)(box3Subject)(val => val - 2)
  .subscribe((newValue) => {
   box1.value = newValue;
   box1Subject.next(newValue);
  });
});

const createBoxStream = element => subject => projection => Rx.Observable
  .fromEvent(element, 'input')
  .map(e => parseInt(e.target.value, 10))
  .merge(subject)
  .map(projection)
  .distinctUntilChanged();

1 个答案:

答案 0 :(得分:0)

我会采用略有不同的方法,我们可以合并来自所有输入的流并相应地更新输入框。这种解决方案适用于任意数量的输入框:

window.addEventListener('DOMContentLoaded', () => {

  const boxesCount = 3;
  const boxes = [];

  let $allBoxesInput = null;

  const keyUp = el => Rx.Observable.fromEvent(el, 'keyup');

  for (let i = 0; i < boxesCount; i++) {
    const el = document.querySelector(`#box${i}`);
    boxes.push(el);
    $allBoxesInput = $allBoxesInput ? 
      Rx.Observable.merge($allBoxesInput, keyUp(el)) : keyUp(el);
  }

  $allBoxesInput.distinctUntilChanged()
    .subscribe(event => {
      // we get all events here
      const id = event.target.id;
      const index = parseInt(id.substr(id.length - 1, id.length));
      const value = event.target.value;
      // update all at the right
      for (let i = index + 1; i < boxes.length; i++) {
        boxes[i].value = parseInt(boxes[i - 1].value) + 1;
      }
    });
});

我使用0启动了ids,使其更符合数组索引:

  <body>
    <input type="text" id="box0">
    <input type="text" id="box1">
    <input type="text" id="box2">
  </body>