I made a toy application to store racing times into localStorage entered by way of HTML input text fields. When I click "Add Race" (save basically) to store a new race's information, the model data that was instantiated when the collection was first created seems to get replaced by the new race information. It's like the collection.fetch() call is destroying any existing collection data. I want to just add a race model data into an existing collection of models. What am I doing wrong?
app.js
// js/app.js
var app = app || {};
var r_obj_arr=[new app.RaceModel({race_name:'Race1', race_date: new Date('November 25, 2013'), race_time: '1:00:01', race_distance: '10K'}), new app.RaceModel({race_name:'Race2', race_date: new Date('November 28, 2013'), race_time: '2:00:01', race_distance: '15K'})];
// Create our global collection of **Races**.
app.Races = new RaceList(r_obj_arr);
$(function() {
// Kick things off by creating the **App**.
new app.RaceView({model: r_obj_arr[0], collection: app.Races});
});
racemodel.js
// Race Model
// ----------
// Our basic **Race** model with default attributes
var app = app || {};
app.RaceModel = Backbone.Model.extend({
initialize: function(attributes) {
this.race_name = attributes.race_name;
this.race_date = attributes.race_date;
this.race_time = attributes.race_time;
this.race_distance = attributes.race_distance;
},
// Default attributes ensure that each todo created has `title` and `completed` keys.
defaults: {
race_name: 'default race name',
race_date: new Date("October 25, 2013"),
race_time: '1:06:25',
race_distance: '5K'
}
});
races.js
var app = app || {};
// Race Collection
// ---------------
// The collection of Races is backed by *localStorage* instead of a remote
// server.
var RaceList = Backbone.Collection.extend({
initialize: function() {
},
// Reference to this collection's model.
model: app.RaceModel,
// Save all of the race items under the `"races-backbone"` namespace.
localStorage: new Backbone.LocalStorage('races-backbone'),
});
// Create our global collection of **Races**.
app.Races = new RaceList();
raceview.js
var app = app || {};
app.RaceView = Backbone.View.extend({
// Instead of generating a new element, bind to the existing skeleton of
// the App already present in the HTML.
el: '#race-display',
model: app.RaceModel,
collection: app.Races,
// Our template for the line of statistics at the bottom of the app.
raceTemplate: _.template( $('#racetemplate').html() ),
// Delegated events for displaying new questions, and clearing existing ones
events: {
'click #add_id': 'addRace'
},
// The RaceView listens for changes to its model, re-rendering. Since there's
// a one-to-one correspondence between a **Question** and a **RaceView** in this
// app, we set a direct reference on the model for convenience.
initialize: function() {
// http://stackoverflow.com/questions/6079055/why-do-bindall-in-backbone-js-views
_.bindAll(this, 'render','addRace');
this.collection.bind('add', this.render);
this.collection.bind('reset', this.render);
this.render();
},
render: function(){
//_.extend is an underscore.js method to combine multiple JSON objects into one
this.$el.html(this.raceTemplate(_.extend({},this.model.toJSON(),{collection_obj: this.collection})));
return this;
},
addRace: function() {
var racename = this.$('#race-name-'+this.collection.length).val();
var racedate = new Date(this.$('#race-date-'+this.collection.length).val());
var racetime = this.$('#race-time-'+this.collection.length).val();
var racemodel = new app.RaceModel({race_name: racename, race_date: racedate, race_time: racetime});
this.collection.add(racemodel);
racemodel.save();
this.collection.fetch(); //refresh from localStorage
alert("Running data added to collection...");
}
});
index.html
<body>
//: some other stuff
<div class="container">
<div class="row">
<h1>Running Times</h1>
<div id="race-display">
</div>
<script type="text/template" id="racetemplate">
<input type="button" id="add_id" value="Add Race" />
<% for(var i=0; i<this.collection.models.length; i++) { %>
<div class="col-md-3">
<input id="race-name-<%= i %>" placeholder="Name of race?" type="text" value="<%= this.collection.models[i].get('race_name')%>" />
<input id="race-date-<%= i %>" placeholder="Date of race?" type="text" value="<%= this.collection.models[i].get('race_date')%>" />
<input id="race-time-<%= i %>" placeholder="Time to finish race?" type="text" value="<%= this.collection.models[i].get('race_time')%>" />
</div>
<% } %>
<div class="col-md-3">
<input id="race-name-<%= this.collection.models.length %>" placeholder="Name of race?" type="text" />
<input id="race-date-<%= this.collection.models.length %>" placeholder="Date of race?" type="text" />
<input id="race-time-<%= this.collection.models.length %>" placeholder="Time to finish race?" type="text" />
</div>
</script>
</div> <!-- row -->
</div> <!-- /container -->
<script src="js/libs/jquery/jquery-min.js"></script>
<script src="js/libs/underscore/underscore-min.js"></script>
<script src="js/libs/backbone/backbone-min.js"></script>
<script src="js/libs/backbone/backbone.localStorage.js"></script>
<!-- <script src="js/libs/backbone/localStorage.js"></script> -->
<!-- <script src="js/libs/backbone/backbone-optamd3-min.js"></script> -->
<script src="js/models/racemodel.js"></script>
<script src="js/collections/races.js"></script>
<script src="js/views/raceview.js"></script>
<script src="js/app.js"></script>
</body>
In your raceview, you need to change your addRace function to create a new race model. You just keep changing the same model rather than creating a new one.
You should have some code something like this: