Перечислите и изолируйте 3 элемента в Cycle.js

Как новичок, я пытаюсь создать список из 3 элементов в Cycle.js. Но в коде есть ошибки. Я сделал jsbin и разместил код ниже

http://jsbin.com/labonut/10/edit?js,output

Проблема: когда я нажимаю на последний флажок, он добавляет новый флажок (чего я не хотел), а старый не меняет свою метку «ВКЛ/ВЫКЛ». Также все, кроме последнего, вообще не реагируют. Что я делаю не так?

const xs = xstream.default;
const {div, span, input, label, makeDOMDriver} = CycleDOM;

function List(sources) {

  sources.DOM
  var vdom$ = xs.fromArray([
    {text: 'Hi'},
    {text: 'My'},
    {text: 'Ho'}
  ])
    .map(x => isolate(ListItem)({Props: xs.of(x), DOM: sources.DOM}))
    .map(x => x.DOM)
    .flatten()
    .fold((x, y) => x.concat([y]), [])
    .map(x => div('.list', x));

  return {
    DOM: vdom$
  }
}

function ListItem(sources) {
  const domSource = sources.DOM;
  const props$ = sources.Props;

  var newValue$ = domSource
    .select('.checker')
    .events('change')
    .map(ev => ev.target.checked);

  var state$ = props$
    .map(props => newValue$
      .map(val => ({
        checked: val,
        text: props.text
      }))
      .startWith(props)
    )
    .flatten();

  var vdom$ = state$
      .map(state => div('.listItem',[
        input('.checker',{attrs: {type: 'checkbox', id: 'toggle'}}),
        label({attrs: {for: 'toggle'}}, state.text),
        " - ",
        span(state.checked ? 'ON' : 'off')
      ]));
  return {
    DOM: vdom$
  }
}


Cycle.run(List, {
  DOM: makeDOMDriver('#app')
});

person Vladimir Buskin    schedule 25.07.2016    source источник


Ответы (2)


Немного укороченный вариант.

1-я строка, получить массив потоков Items Dom.

2-я строка, затем объедините потоки в один поток и оберните элементы в родительский div

function List(sources) {

  var props = [
    {text: 'Hi'},
    {text: 'My'},
    {text: 'Ho'}
  ];

  var items = props.map(x => isolate(ListItem)({Props: xs.of(x), DOM: sources.DOM}).DOM);

  var vdom$ = xs.combine(...items).map(x => div('.list', x));

  return {
    DOM: vdom$
  }
}
person Vladimir Buskin    schedule 26.07.2016
comment
Мне этот ответ больше нравится! Я добавил версию, совместимую с es5, в свой ответ. - person bloodyKnuckles; 26.07.2016
comment
Я предлагаю вам сделать этот ответ выбранным ответом. Я рад помочь (и научиться), но я думаю, что людям, которые найдут этот вопрос, лучше подойдет этот ответ. - person bloodyKnuckles; 27.07.2016
comment
Хорошо, говорит stackoverflow, вы можете принять свой собственный ответ через 5 часов, уже слишком поздно, похоже - person Vladimir Buskin; 27.07.2016
comment
Ах. Я переместил версию, которую вы вдохновили, в начало моего ответа. - person bloodyKnuckles; 27.07.2016

Вдохновленный ответом Владимира, вот вариант его ответа "старой школы" и улучшение моего исходного ответа:

function List(sources) {

  const props = [
    {text: 'Hi'},
    {text: 'My'},
    {text: 'Ho'}
  ];

  var items = props.map(x => isolate(ListItem)({Props: xs.of(x), DOM: sources.DOM}).DOM);

  const vdom$ = xs.combine.apply(null, items)
    .map(x => div('.list', x));

  return {
    DOM: vdom$
  };
}

Демо старой школы JSBin


(Оригинальный ответ.)

Похоже, проблема в вашей функции List. Честно говоря, я не знаю причину, но придумал другое решение:

function List(sources) {

  const props = [
    {text: 'Hi'},
    {text: 'My'},
    {text: 'Ho'}
  ];

  function isolateList (props) {
    return props.reduce(function (prev, prop) {
      return prev.concat(isolate(ListItem)({Props: xs.of(prop), DOM: sources.DOM}).DOM);
    }, []);
  }

  const vdom$ = xs.combine.apply(null, isolateList(props))
    .map(x => div('.list', x));

  return {
    DOM: vdom$
  };
}

демонстрация JSBin

Одно отличие здесь в том, что я не передаю элементы в объекте props. Вместо этого я передаю массив функции, которая reduces передает реквизиты в массив потоков элементов списка vdom, а затем applying этот массив в xstream combine factory.

person bloodyKnuckles    schedule 26.07.2016
comment
да, вы правы, нужно время, чтобы понять поток - person Vladimir Buskin; 26.07.2016