Skip to content

Instantly share code, notes, and snippets.

@dhollenbeck
Created January 24, 2012 22:12
Show Gist options
  • Save dhollenbeck/1673049 to your computer and use it in GitHub Desktop.
Save dhollenbeck/1673049 to your computer and use it in GitHub Desktop.
backbone.js collection with nested models for a nested list menu
App.collections.Menuitems = App.collections.Collection.extend({
model : App.models.Menuitem,
url : './api/menuitems',
initialize: function(options){
this.bind('reset', this.relationships); //collection loads so calculate relationships
},
relationships: function(){
this.relations = _.groupBy(this.models, this.parent);
},
//return an array of root models
root: function(){
if(!this.relations) this.relationships();
return this.relations[0];
},
//return an array of child models
children: function(model){
if(!this.relations) this.relationships();
return (typeof this.relations[model.id] === 'undefined')? [] : this.relations[model.id];
},
//return parent_id or 0 if model.parent_id is undefined
parent: function(model){
var parent_id = model.get('parent_id');
return (!parent_id)? 0: parent_id;
}
});
<script type="text/template" id="menu-item-template"><a id="menu-item-<%=id %>" href="<%=href %>" title="<%= title %>"><%=text %></a></script>
<script type="text/template" id="menu-template"><h1>Menu</h1></script>
{"result":[
{"id":1,"href":"#\/","text":"Home","title":"Home"},
{"id":2,"href":"#\/persons","text":"Persons","title":"Person listing"},
{"id":4,"href":"#\/xxxx","text":"Broken link","title":""},
{"id":5,"href":"http:\/\/www.google.com","text":"www.google.com","title":"","parent_id":4},
{"id":6,"href":"http:\/\/www.ibm.com","text":"www.ibm.com","title":"","parent_id":5}
]}
App.views.Menu = App.views.View.extend({
//define this.el, the wrapper element
//id: '',
tagName: 'div',
className: 'menu',
id: 'menu',
//template function
template: _.template($('#menu-template').html()),
initialize: function(options) {
if (!options.collection) throw 'no collection provided';
//listen on non-this events
_.bindAll(this, 'render');
this.collection.bind('reset', this.render); //collection loaded
},
events: {
//"click": "console"
},
close: function (){
this.unbind();
this.collection.unbind();
},
/***************************************
Render the view into the view's element
****************************************/
render: function (event){
var content = this.template({}); //compiling template = create DOM fragment
var $el = $(this.el);
$el.html(content);
//render list menu
$el.append(this.renderMenu(this.collection.root()));
return this;
},
/**********************************************
Render list menu. Input is an array of models.
Output is DOM fragment.
**********************************************/
renderMenu: function(list){
if(_.size(list) === 0) {return null;}
var $dom = $('<ul></ul>');
_.each(list, function(model){
$dom.append(this.renderMenuItem(model));
var kids = this.collection.children(model);
$dom.find(':last').append(this.renderMenu(kids)); //recursive
}, this);
return $dom;
},
// returns a DOM element fragment for a single menu item
renderMenuItem: function (model){
var view = new App.views.Menuitem({model: model});
return view.render().el;
},
console: function (event){
console.log(event, 'event');
}
});
App.views.Menuitem = App.views.View.extend({
//define this.el, the wrapper element
//el: $('#menu'), //used in cases where the view wrapper already exists in the DOM
tagName: 'li',
//id: '',
//className: 'menuitem',
// Cache the template function for a single item.
template: _.template($('#menu-item-template').html()),
initialize: function(options) {
_.bindAll(this, 'render');
this.model.bind('change', this.render);
},
events: {
},
close: function (){
this.unbind();
this.model.unbind();
},
//render the view using a template
render: function (event) {
var content = this.template(this.model.toJSON());
$(this.el).html(content);
return this;
}
});
@averagemind
Copy link

hi dhollenbeck,

your code helped me to create this http://bit.ly/1cyFaPY and http://bit.ly/1chPnkS.

thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment