I'm working on todo list sample app using Cycle.js and I came across following problem. I'm trying handle add new todo item when user clicks Add button, which works fine, but on the other hand I have a stream which provides text input change events and when combined with the click stream it makes my app to add new todo items even in case when the text input is changed, but the Add button is not clicked e.g. focus out. What is the approach in such cases? Can I just eliminate todoChange$ stream and access DOM from addClick$ stream directly, or it would be against Cycle.js philosophy?
JS Bin: https://jsbin.com/wugawaheni/edit?js,console,output
const xs = xstream.default;
const {div, input, p, makeDOMDriver} = CycleDOM;
const intent = (DOMSource) => {
const addClick$ = DOMSource.select('.add').events('click').map(ev => true);
const todoChange$ = DOMSource.select('.todo').events('change').map(ev => ev.target.value);
return { addClick$, todoChange$ };
};
const model = (addClick$, todoChange$) => {
const add$ = addClick$.startWith(false);
const todo$ = todoChange$.startWith('');
return xs.combine(add$, todo$)
.map((combined$) => combined$[1])
.fold((todos, todo) => {
todo.trim() && todos.push(todo);
return todos;
}, []);
};
const view = state$ => state$.map(todos => div([
input({attrs: {type: 'text', class: 'todo'}}),
input({attrs: {type: 'submit', value: 'Add', class: 'add'}}),
div(todos.map(todo => p(todo)))
]));
const main = (sources) => {
const { addClick$, todoChange$ } = intent(sources.DOM);
const state$ = model(addClick$, todoChange$);
const vdom$ = view(state$);
return {
DOM: vdom$
};
};
Cycle.run(main, {
DOM: makeDOMDriver('#app')
});