I'm trying to do the obvious, update the view on model change (in this case a new one is added). It actually works, but the problem is the whole view gets rerendered when a model is added. The new data is actually not really being appended to the view but pretty much everything is being reloaded using the "html()" method.
Do you know a way to solve this in a more efficient way?
<body>
<div class="page"></div>
<script type="text/template" id="myTemplate">
<ul>
<% for (var i = 0; i < library.length; i++) { %>
<li> <%= library[i].title %></li>
<li> <%= library[i].artist %></li>
<li> <%= library[i].track %></li>
<br>
<% } %>
</ul>
<input id="inputTitle" placeholder="enter title" type="text"> <br>
<input id="inputArtist" placeholder="enter artist" type="text"> <br>
<input id="inputTrack" placeholder="enter title" type="number"> <br>
<button id="addItem">add</button>
</script>
<script type="text/javascript">
var Song = Backbone.Model.extend({
initialize: function()
{
this.on('add',function(){
albumview.render();
});
}
,defaults:
{
title: "no title",
artist: "no artist",
track: 0
}
});
var AlbumView = Backbone.View.extend({
initialize: function()
{
this.render();
},
render: function()
{
var self = this;
var output = _.template($('#myTemplate').html(),{'library': self.collection.toJSON()});
self.$el.html(output);
return self;
},
events:
{
'click #addItem' : 'addItem'
},
addItem: function()
{
var TitleValue = $('#inputTitle').val();
var ArtistValue = $('#inputArtist').val();
var TrackValue = $('#inputTrack').val();
var self = this;
self.collection.push({
title: TitleValue,
artist: ArtistValue,
track: TrackValue
});
}
});
var Album = Backbone.Collection.extend({
model: Song
});
var song1 = new Song({
title: "Trouble on my mind",
artist: "Pusha-T",
track: 3
});
var song2 = new Song({
title: "Yonkers",
artist: "Tyler The Creator",
track: 2
});
var album = new Album([song1,song2]);
var albumview = new AlbumView({
el: '.page',
collection: album
});
</script>
</body>
First, I'd avoid calling your view's render method from inside the model. Second, are you sure you want a new albumview for each song? It seems like your albumview, which maintains a reference to your album collection, just needs a songview, or some other such construct:
var AlbumView = Backbone.View.extend({
initialize: function () {
this.listenTo(this.collection, 'reset', this.render);
this.listenTo(this.collection, 'add', this.addOne);
},
render: function () {
this.addAll();
return this;
},
addAll: function () {
this.$el.empty();
this.collection.each(this.addOne, this);
},
addOne: function (song) {
var songView = new SongView({ model: song });
this.$el.append(songView.render().el);
}
});
var SongView = Backbone.View.extend({
render: function () {
// whatever you would do for just one song
}
});
This is a common pattern for rendering a collection (album) view and an item (song) view.