Following up on How to structure rxjs code, concerning how to structure a widget with subwidget when using rx, how would you structure rx code where the subwidgets are data-driven?
As a toy problem, suppose you have an external source (e.g. web service) streaming a list of stocks to watch, with value, high, low, etc. So you have an Observable stream like (time goes down):
[{id: 'csco', value: 12, high: 20, low: 10}]
[{id: 'csco', value: 12, high: 20, low: 8},
{id: 'aapl', value: 29, high: 30, low: 20}]
You need to build a widget for each stock symbol. So the pattern in the previous question has to be modified. There's not one child, and a child is created/destroyed based on the input stream, e.g. we create a child for 'csco' on the 1st event. On the 2nd event the 'csco' child gets an update (low: 8) and we create a child for 'aapl'.
You could move the subwidget creation to the subscribe:
function widget(state) {
state = state.share();
var children = {};
state.subscribe(function (s) {
findNew(children, s).forEach(function (stock) {
children[stock] = subwidget(state.select(findById.bind(null, stock)));
});
// ... delete old ones similarly
});
}
This introduces an ordering problem: the child doesn't get the event that cause it to be created. You can work around this by doing something like state.repeat(1)
, or state.startsWith(s).select(...)
, but it looks a bit odd.
Suppose the children are also returning streams. E.g. maybe the user manipulates the children to model different positions, so we want to get some computation back from the children and display an overall total, or other metric, in widget.
Do you create a Subject in widget() and push on it the streams from the children? Like
var positions = new Rx.Subject();
positions.mergeAll().subscribe(displayTotal);
...
.. subscribe(function(s) {
child = subwidget(...)
children[stock] = child.disposable;
positions.onNext(child.position);
This all seems pretty clunky. Is there a better way to organize it? I tried modeling it as a stream of streams, one per child, and merging the outputs. This worked poorly. It was hard to keep track of the inner subscriptions, or have multiple streams output from the children.