I've found another solution, which seems to me most "pure" (especially if Bus is considered harmful): instead of calling render as a method, trigger it through a stream (I now provide more full snippet from my app, hopefully details wouldnt distract from Bacon parts):
function MapComponent(coreStreams) {
var render = function () {
var view = new ol.View({center: ol.proj.fromLonLat([37.41, 8.82]), zoom: 4});
var map = new ol.Map({target: 'map', view: view, layers:[new ol.layer.Tile({source: new ol.source.MapQuest({layer: 'sat'})})]});
return {coords: Bacon.fromEvent(view, 'change:center').map(function (e) {return ol.proj.toLonLat(e.target.get(e.key));})};
};
var renderResults = Bacon.when([coreStreams.render], render);
renderResults.onValue(_.noop); //without this, map wouldn't render
this.output = {coords: renderResults.flatMap(_.property("coords")).toProperty([0, 0])};
}
function InfoPanelComponent(coreStreams, mapStreams) {
var render = function (render, coords) {
return new Ractive({
el: 'infoPanel',
template: 'Coords: {{coords[0]}}, {{coords[1]}}',
data: {coords: coords}
});
};
var renderResults = Bacon.when([coreStreams.render, mapStreams.coords], render);
renderResults.onValue(_.noop); //ditto for infoPanel - without this "sink", it wouldnt render until first event come to the function below
Bacon.when([renderResults.toProperty(), mapStreams.coords.changes()], function (ractive, coords) {
ractive.set('coords', coords);
}).onValue(_.noop); // agan - without the subscriber, changes wouldn't be processed
}
var coreStreams = {render: Bacon.later(100, true)};
var mapStreams = new MapComponent(coreStreams).output;
new InfoPanelComponent(coreStreams, mapStreams);
However, I have two problems here:
First, I had to add artificial onValue() "sinks", because when() on itself doesn't considered subscription.
Second, flatMap() of Properties is EventStream, not Property, so I had to add .toProperty outside of render() - hence, I cannot set initial value of property based on results of first render. In my example, I just could use same hard-coded coordinates I used in construction of View, but in other components initial values would be computed during render somehow.
I like this variant better, but feel it can be improved further.
Sincerely,
Dmitry