Skip to content

Instantly share code, notes, and snippets.

@milankinen
Created March 5, 2016 18:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milankinen/a990cd845f1c9670ee1e to your computer and use it in GitHub Desktop.
Save milankinen/a990cd845f1c9670ee1e to your computer and use it in GitHub Desktop.
Dynamic CycleJS counters
function Counter({signals, DOM: {render, h, events}, title}, initial$ = Observable.just(0)) {
const model = (signals, initial$) =>
initial$.first().concat(signals.in("inc").merge(signals.in("dec"))).scan((s, a) => s + a).share()
const view = (counter$) =>
[counter$, render(counter$.map(count =>
h("div", [
h("button.increment", "Increment"),
h("button.decrement", "Decrement"),
h("p", title + ": " + count)
])))]
const intent = ([value$, dom$]) => ({
DOM: dom$,
signals: signals.out({
inc: events(dom$, ".increment", "click").map(_ => +1),
dec: events(dom$, ".decrement", "click").map(_ => -1)
}),
value$
})
return intent(view(model(signals, initial$)))
}
function main({signals, DOM}) {
const {h, render, events} = DOM
return intent(view(model(signals)))
function model(signals) {
const counters$ =
signals.in("add").map(() => s => [...s, 0])
.merge(signals.in("rm").map(() => ([x, ...xs]) => xs))
.merge(signals.in("val").map(({val, idx}) => s => s.map((v, i) => i === idx ? val : v)))
.startWith([0])
.scan((s, mod) => mod(s))
.shareReplay(1)
const num$ = counters$.map(c => c.length)
return {counters$, num$}
}
function view({counters$}) {
const counters$$ = counters$.map(counters => counters.map((c, i) => Counter({
signals: signals.in(`counter.${i}`),
DOM,
title: `Counter #${i}`
}, Observable.just(c)))).shareReplay(1)
const vdom$ = counters$$
.flatMapLatest(counters => counters.length ? Observable.combineLatest(...counters.map(c => c.DOM)) : Observable.just([]))
.map(counters => h("div", [
h("button.add", "++"),
h("button.rm", "--"),
h("hr"),
...counters
]))
return {counters$$, dom$: render(vdom$)}
}
function intent({counters$$, dom$}) {
const add$ = events(dom$, ".add", "click")
const rm$ = events(dom$, ".rm", "click")
const val$ = counters$$
.map(counters => Observable.merge(counters.map((c, idx) => c.value$.map(val => ({val, idx})))))
.switch()
const signal$ = counters$$
.map(counters => counters.reduce((acc, c, i) => ({...acc, [`counter.${i}`]: c.signals}), {}))
.map(counterSignals => signals.out({
...counterSignals,
add: add$,
rm: rm$,
val: val$
}))
.switch()
return {DOM: dom$, signals: signal$}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment