This is a very interesting read with a lot of interesting topics being discussed.
On "Views as components"
> Each view can include other ‘sub’ views, which can themselves include subviews and so on.
This is something that is missing from Backbone and it's something that always comes up, even when doing something as simple as a Todo list. In the Backbone Todo list example[1] you there are methods on the "parent view" (eg, the List view or the App view) to addOne and addAll (rendering the Item views).
So the concept of "sub views" is definitely needed but what I'd like to know, from SoundCloud's perspective, what were the arguments for/against implementing this functionality from within the templates and not from some place else, eg. the parent view's or the sub view's constructor (as a parent/child attribute) or initialize method.
> Each view is responsible for its own setup, events, data, and clean up.
Having already implemented the "sub views" concept it seems perfectly logical to allow a parent view to inherit DOM events from its children. Considering the Todo list example, and without using Backbone, how would you implement DOM events on the Todo items? You wouldn't bind events on each item's DOM element - that's just crazy. You would bind the events on the list (just once, for all items) and find a way to know on which item the event was triggered. In other words, you would use $('parent').on('event', 'child' ... ) and not $('child').bind.
It seems that with Backbone people have forgotten this practice, in a way similar to how people started using inefficient DOM selectors when jQuery came along.
So, when implementing the "sub view"/"parent view" concept, what would make perfect sense is to specify if the sub view's DOM events should be bounded on the parent view's DOM element. What I'd like to know is if SoundCloud has considered doing this and if yes why they have decided against it.
>what were the arguments for/against implementing this functionality from within the templates and not from some place else
It is still quite possible for parent views to construct subviews and insert them into its own DOM at any time, but due to the nature of our views, many of them are UI components, and so it made sense to be able to define both the subview as well as its position at the same time. It makes writing a view with subviews very easy. You simply use the Handlebars helper exactly where you want that view and the rest is taken care of for you.
>You would bind the events on the list (just once, for all items) and find a way to know on which item the event was triggered.
Yes, that's a very common approach to handing DOM events, but it ran against our belief that views should be independent. If a view can only work in a particular situation (eg: nested inside a list which handles its events), then that creates hard dependencies between those two views and you can quickly get into a mess. Event delegation is definitely used in Next, but only at a per-view level. It is a sacrifice (I would posit that it's a minor sacrifice), but the benefits are highly independent and reusable views. We do take advantage of this, too: for example, if you look at the waveform in the player, and the miniature waveform in the header which shows your currently-playing sound (visible in the screenshot), that is the exact same view. Because they handle everything themselves, there was absolute minimum work needed to add that feature.
Thanks for the feedback and the interest,
Nick.
Note that I'm just talking about our particular project: YMMV, and using event delegation in higher level views for your own project might provide bigger wins in terms of performance or maintainability.
> It makes writing a view with subviews very easy. You simply use the Handlebars helper exactly where you want that view and the rest is taken care of for you.
It does indeed look very simple and easy but what I would be concerned about is that you have logic in your views that perhaps shouldn't be there. Your views are now dependent on the template language/parser you are using. Have you tried any other approaches that didn't work so well/easy before coming to this solution?
> If a view can only work in a particular situation (eg: nested inside a list which handles its events), then that creates hard dependencies between those two views and you can quickly get into a mess.
Agree. But how about having per view instance dependency instead of per view constructor. For example,
So your user-badge view can bind its events on the parent_view.el (if available), otherwise on itself. Backbone does this in a way on its delegateEvents method. If there is no selector specified in your event it uses bind on this.$el, otherwise it uses this.$el.delegate.
That's not a bad idea actually -- I might look into that. With only one subview, it ends up with the same amount of handlers, so the benefit would only be seen in list-like views with repeated subviews, right?
> This is something that is missing from Backbone
> and it's something that always comes up
... not so much missing as agnostic. You're quite right that subviews always exist in complex applications, but they're best handled in different ways depending on your templating / HTML-generation library of choice, and your app's architecture. Backbone doesn't want to force you to necessarily have a complete static hierarchy of View objects from the root DOM element down to the bottom ... many applications don't need or benefit from it. That said, if you've got a piece of functionality that you think would help with subviews in most Backbone projects, it would make for a great ticket or pull request.
> You would bind the events on the list (just once,
> for all items) and find a way to know on which
> item the event was triggered.
Yep, and Backbone encourages that kind of delegation by default at the view level ... mostly for reasons of statelessness rather than performance. It's awfully nice to know that all of your events are always bound and ready on any given view, regardless of whether or not that view has any HTML yet, or has even been inserted into the DOM yet.
That said, binding to individual elements isn't problematic unless you're truly doing too much of it. 20 songs each with their own bound callbacks would be fine, but 2,000 songs wouldn't be. When to delegate for performance follows the same reasoning as it would in a plain 'ol jQuery app, and is touched on briefly in the FAQ: http://backbonejs.org/#FAQ-tim-toady
For what it's worth, here's an example of a Backbone view that's using delegation and a single event listener as a callback for all of the individual blocks in the charts: http://blog.documentcloud.org/blog/2011/10/entity-charts/
> It seems that with Backbone people have forgotten this practice
To be fair, Backbone's events hash idiom is implemented using event delegation straight out of the box. It's not forgotten at all.
Although to your point: since Backbone offers no OOTB mechanism for sub-views, it offers no OOTB support for event delegation on a parent view. I just wanted to clarify where that line is drawn wrt event delegation being "forgotten".
> I just wanted to clarify where that line is drawn wrt event delegation being "forgotten".
Yes, I should have been more clear on that. I mentioned that because SC says that they may have a view (DOM element) that contains a single button (or whatever). This means they bind events on each one of those buttons, even if they have 100 of those at any given time on the DOM. Maybe they have some other form of event delegation but they haven't mentioned it.
On "Views as components"
> Each view can include other ‘sub’ views, which can themselves include subviews and so on.
This is something that is missing from Backbone and it's something that always comes up, even when doing something as simple as a Todo list. In the Backbone Todo list example[1] you there are methods on the "parent view" (eg, the List view or the App view) to addOne and addAll (rendering the Item views).
So the concept of "sub views" is definitely needed but what I'd like to know, from SoundCloud's perspective, what were the arguments for/against implementing this functionality from within the templates and not from some place else, eg. the parent view's or the sub view's constructor (as a parent/child attribute) or initialize method.
> Each view is responsible for its own setup, events, data, and clean up.
Having already implemented the "sub views" concept it seems perfectly logical to allow a parent view to inherit DOM events from its children. Considering the Todo list example, and without using Backbone, how would you implement DOM events on the Todo items? You wouldn't bind events on each item's DOM element - that's just crazy. You would bind the events on the list (just once, for all items) and find a way to know on which item the event was triggered. In other words, you would use $('parent').on('event', 'child' ... ) and not $('child').bind.
It seems that with Backbone people have forgotten this practice, in a way similar to how people started using inefficient DOM selectors when jQuery came along.
So, when implementing the "sub view"/"parent view" concept, what would make perfect sense is to specify if the sub view's DOM events should be bounded on the parent view's DOM element. What I'd like to know is if SoundCloud has considered doing this and if yes why they have decided against it.
[1] http://documentcloud.github.com/backbone/examples/todos/todo...