Short story... I have nested views but only the top level view can work with events because I am only passing in the 'el' property to the top level view.
Long story...
I am creating a timeline project using backbone as JS/GUI client side app. My template for rendering the horizontal timeline is like this:
<script type="text/template"开发者_Python百科; id="yearGroups">
<![CDATA[
<% _.each(columns, function(item,i) { %>
<div class="yearGroup">
<h2><%= item.yearLabel %></h2>
<div class="years">
<% _.each(item.years, function(year, b) { %>
<div class="year">
<% _.each(year.searchGroups, function(sg, sg_index) { %>
<%= jQuery(sg.viewEl).html() %>
<% }); %>
</div>
<% }); %>
</div>
</div>
<% }); %>
]]>
</script>
There can be multiple searches and therefore multiple searchGroups
per year.
Each searchGroup
contains eventBlocks
as a wrapper for each search result.
Below is a code snippet from the loop which creates the SearchGroupViews
(which creates the eventBlocks
not shown here).
var events = eventCollection.getEventsInYear(year);
if(events.length > 0) {
var sgv = new SearchGroupView({results: events, searchID: 'search1'});
this.searchGroups.push(sgv);
renderedResults.push({viewEl:sgv.render().el});
}
renderedResults
is then eventually passed through to the template like this:
$(this.el).html(this.template({columns:col}));
... and rendered under each .year using:
jQuery(sg.viewEl).html().
All of this means that my nested views don't receive any events because they don't have a container div passed in using the 'el' attribute. They don't have a container because that's rendered after all the views are built (see first code block).
My current solution is to use a global eventManager
that can be used as an event handler to notify views when the top level view calls an eventManger.trigger(..)
. This is not ideal.
There must be a solution that allows my nested views to pick up on the events after they have been rendered? Or do I need to pre-render the top level view template and specify el attributes like {el: '.year.yearID-1984'}
and {el: '.searchGroup.groupID-6'}
?
Ideally I could render sg.viewEl
and not simply the html output from that object and the view would then be self aware of where it is. ... but I know that's not possible :(
Hope this is clear.
I implemented an ok solution close to what was described in my question...
//global event notifier system
window.vent = _.extend({}, Backbone.Events);
window.app = new TimelineRouter();
After rendering the top level view, I then call:
window.vent.trigger('ev:redelegate', {});
This event is then captured in each view init function....
this.model.view = this;
var _this = this;
window.vent.bind('ev:redelegate', function(event) {
var nid = _this.model.get('nid');
_this.el = $('.nid-'+nid);
_this.delegateEvents();
});
...so that the view can update the el property. This all relies on a unique class name being used to find the el (eg, class="nid-1234").
I'm guessing this would then be the same as setting the view el property on init given that I know the id it's based on. This assumes that backbone uses .live(..) for finding the el: ".nid-1234" DOM obj.
精彩评论