Closed Earthstar closed 6 years ago
Good question. This goes for pretty much any parent to many, many child views. The simplest way is to have an event bus to publish to.
var bus = new Torso.Events
You can namespace with the view type and the action that is being performed. You can also add the child view as a payload if you need the parent to handle who sent it.
myChildViewMethod: function() {
bus.trigger('todoView:requestPopup', this)
}
If you want to use your own list view bus, you can pass a list view bus to the child views by overriding the generateChildArgs (which, should not be double as it is meant to be overridden)
__generateChildArgs: function(model) {
var args = Torso.ListView.prototype.__generateChildArgs.call(this, model);
args.listBus = this.bus;
return args;
}
We could think about adding an automatic pub-sub system between the child views and the parent where you tell the parent to listen for specific events on every child it creates. You could roll your own version of this by extending ListView and creating "on" callbacks to listview's 'child-view-added' and 'child-view-removed' events.
Interesting. The context is that I had a very long, protracted discussion about whether to use events or callbacks for child -> parent communication, and that stuff like this should probably be added to the "cookbook."
Since Backbone/Torso uses events for communication, it would make sense to me if events fired on child item views bubble up to the parent list view, analogous to how events on models bubble up to the collection. Then, you wouldn't have to pass a 'bus' object around.
Interesting, you're saying a child view's events would be republished by their parents?
Yes, so you'd be able to listen to events on the parent directly (although this might only make sense for List views?) What do you think? I'm trying to improve Torso's "developer ergonomics" so we don't have to pass arguments or override things all the time to get the behavior we want.
I like that a parent might automatically listen to all events of a tracked or owned child and let the parent react to them, but I don't like the parent re-triggering events. Controlling events will be difficult and knowing the originating triggerer will become a problem. Name claches will also become an issue between parent and child and what is the point?
If the parent automatically listens to the "all" event during child registration, torso views could invoke a method with the name of the event, the triggerer, and the payload. That's nice, except the method you'd override would look pretty stupid:
function(childview, eventName, payload) {
if (eventName = 'foo') {
...
} else if (eventName = 'bar') {
...
} // and so on
}
I guess you could go a step further, and for any parent, the programmer can register a set of events they care about, and during the child registration, only bind to those events. Just a short hand and fail-safe way of listening to children views.
What are your thoughts on allowing a parent to register child views like this? If we place the logic at the register/unregister child views, then even a view with many child views would be able to listen without much effort.
childEvents: {
requestPopup: 'handlePopupRequest',
anotherChildViewEventName: 'handler'
},
handlePopupRequest: function(childView, payload) {
// do something
},
registerTrackedView: function(view, options) {
var trackedViewsHash = this.__getTrackedViewsHash(options);
trackedViewsHash[view.cid] = view;
_.each(this.childEvents, function(eventCallback, eventName) {
this.listenTo(view, eventName, _.bind(this[eventCallback], this, view, /*have to think how to get payload*/), this);
}
return view;
},
unregisterTrackedView: function(view, options) {
var trackedViewsHash = this.__getTrackedViewsHash(options);
delete trackedViewsHash[view.cid];
this.stopListening(view);
return view;
},
The only thing I don't like about this is matching which child views you want to listen to.
If I had 10 child view A's and 10 child view B's, and I only wanted to listen to A's 'requestPopup', how would I target those views?
I'm reopening because while there are ways to handle this communication, I agree that there could be a better way to open communication channels between list views and their children views, especially when there are multiple instances of the same list view (and therefore some identifier has to be passed in with the event). I think a dialog on this concept is worth it.
If possible, I'd like to limit:
@mandragorn @Earthstar I'd like us to investigate scoped events buses. Like a pod-level bus. Keeping the independence of child views, but gives a more useful scope than only being application-level.
this.on('item-view-added', (data) => {
this.listenTo(data.view, 'my-event', this.doSomething);
});
this.on('item-view-removed', (data) => {
this.stopListening(data.view, 'my-event', this.doSomething);
});
For example, the child item view has a button that, when pressed, should pop up a modal controlled by the parent view.