Search code examples
javascriptjqueryknockout.jsbackbone.js-collectionsknockback.js

Knockback.js backbone collection only adds first element to UI


I'm trying to set something new up with Knockback.js, and right now I'm running into an issue with the knockout/knockback integration. The problem is, I've successfully written an event handler which adds a new model to the Objectives collection, but the UI only registers and adds the first such addition. It does successfully add the new objective to the list, but only the first one--after that, while the collection does successfully add a new model to the list, it doesn't appear in the UI.

<a class="btn" id="click">Click me!</a>
<div id="objectives" data-bind="foreach: objectives">
    <h3 data-bind="text: name"></h3>
</div>

And this script:

// Knockback script MUST be located at bottom of the page
$(document).ready(new function() {
// instantiate the router and start listening for URL changes
var page_router = new PageRouter();
Backbone.history.start();

// Get JSON value
var objectives;
$.getJSON('json.php', {table: 'objectives'}).done(function(data) {
    objectives = new ObjectiveCollection(data);
    var view_model = {
        objectives: kb.collectionObservable(objectives, {view_model: kb.ViewModel})
    };
    ko.applyBindings(view_model, $('#objectives').get(0));
});
$('#click').click(function() {
    var objective_model = new Objective({category: 3, name: Math.random(), descriptor: 'What up'});
    objectives.add(objective_model);
    console.log(objectives);
});
});

Where the only custom models are as seen here:

/**
 *  Objectives model
 */
var Objective = Backbone.Model.extend({
// Defaults
defaults: {
    id: null,
    category: null,
    weight: null,
    name: null,
    descriptor: null
},
// Url to pass to
url : function() {
    // Important! It's got to know where to send its REST calls. 
    // In this case, POST to '/donuts' and PUT to '/donuts/:id'
    return this.id ? '/objectives/' + this.id : '/objectives'; 
}

});
/**
 *  Basic objectives collection
 */
var ObjectiveCollection = Backbone.Collection.extend({
    model: Objective,
initialize: function(models,options) {}
});

Solution

  • Turns out, the issue was located here:

    var Objective = Backbone.Model.extend({
      // Defaults
      defaults: {
        id: null,
        category: null,
        weight: null,
        name: null,
        descriptor: null
    }
    

    It kept generating models with an ID of null, and the program will only display objects with a unique ID. Since the ID defaults to null, it will consider two objects without defined IDs as being the same. By erasing the id: null; line, this problem stopped being an issue.