The answer: it should've been .merge in button's model, not .combineLatest. Obviously
Intended behaviour:
- click the button
- while the request is sent, display 'Loading...'
- when the response is received, display original button
- there are random color changes when the button is clicked (just to see that everything works)
Problem:
Everything works until superagent encounters an error. Then everything breaks and no more requests are sent out.
Tried to catch
according to https://github.com/cyclejs/cycle-http-driver/issues/8
However, this somehow broke the cycle of things:
- The button turns into 'Loading...' and never reverts to original state
I've sprinkled some console.log
s around, and here's what happens:
- button's
click
is triggered and registered in the button's model (inloading$
) - HTTP request is sent, trggers an error (in main's
view
scatch
) - the response is registered in the button's model (in
done$
) - For some reason
Rx.Observable.combineLatest
produces the result ofloading$
(not ofdone$
)
Code:
main.js
import {run} from '@cycle/core';
import {makeDOMDriver} from '@cycle/dom';
import {makeHTTPDriver} from '@cycle/http';
import main from 'components/main/index';
run(main, {
DOM: makeDOMDriver('#app'),
HTTP: makeHTTPDriver({autoSubscribe: true})
});
index.js
/** @jsx hJSX */
import {hJSX} from '@cycle/dom';
import Rx from 'rx';
import _ from 'lodash';
/*
* Componens
*/
import SimpleButton from 'components/buttons/simple/index';
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function view (sources){
const httpResponse$$ = sources.HTTP;
const httpResponse$ = httpResponse$$.flatMap(x$ => {
return x$.catch(function(e){
console.log('error: ', e);
return Rx.Observable.just({text: `Error: ${e}`});
})
});
const finalSources = _.merge(sources, {response$: httpResponse$.map(({text}) => text)});
const {DOM, intent} = SimpleButton(finalSources);
const colors$ = intent.map(() => getRandomColor());
const VTree = Rx.Observable.combineLatest(
colors$.startWith(''),
DOM, (color, DOM) => <div style={{color: color}}>Click the button {DOM}</div>
);
const url = 'http://date.jsontest.c';
return {
DOM: VTree,
HTTP: intent.map(() => url)
}
}
export default function(sources){
return view(sources);
};
components/buttons/simple/index
/** @jsx hJSX */
import {hJSX} from '@cycle/dom';
import Rx from 'rx';
import _ from 'lodash';
import './style.styl';
const state = {
LOADING: 0,
DONE: 1
};
function intent({DOM}){
const click$ = DOM.select('#simple')
.events('click')
.map((e) => {e.stopPropagation(); return e.target;});
return {
click$: click$
}
}
function model({response$}, {click$}){
const loading$ = click$.map(() => {console.log('click'); return state.LOADING});
const done$ = response$.map(() => {console.log('done'); return state.DONE});
return Rx.Observable.combineLatest(loading$, done$, (s) => {console.log(s); return s});
};
function view(model$){
const defaultDOM = <div id="simple">Btn</div>;
return model$.map((s) => {
if(s === state.LOADING){
return <div>Loading</div>;
} else {
return defaultDOM;
}
}).startWith(defaultDOM);
}
export default function(sources){
const actions = intent(sources);
const model$ = model(sources, actions);
const view$ = view(model$);
return {
DOM: view$,
intent: actions.click$
};
};