Search code examples
javascriptjsonbackbone.jscollectionsunderscore.js

Populate Backbone.js JSON response into nested collections inside nested collections/models


My problem is that I am just starting out with Backbone.js and are having trouble wrapping my head around a complex problem. I want to save a form that have infinite fields, and some of the fields also needs to have infinite options. I'm just worried I might have started at the wrong end with a JSON response, instead of building the models/collections first. Here is a short pseudocode of what I try to achieve.

id:
parent: <blockid>
fields: array(
  id:
  title:
  helpertext
  options: array(
    id:
    type:
    value:
  )
)

Currently I am working with a faked JSON response from the server, which I built from scratch, and now I want to divide it into models and collections on the client side.

//Fake a server response
var JSONresponse = {
    "formid":"1",
    "fields":[
        {
            "fieldid":"1",
            "title":"Empty title",
            "helper":"Helper text",
            "type":"radio",
            "options":[
                {
                    "optionid":"1",
                    "value":"Empty option.."
                },
                {
                    "optionid":"2",
                    "value":"Empty option.."
                }
            ]
        },
        {
            // fieldid2
        }
    ]
};

The idea is to add fields as I see fit, and then if the field type is radio/checkbox/ul/ol there must also be an "options" array within the field.

My work so far:

    var app = {};
    app.Models = {};
    app.Collections = {};
    app.View = {};

    app.Models.Option = Backbone.Model.extend({
    });

    app.Collections.Options = Backbone.Collection.extend({
        model: app.Models.Option
    });

    app.Models.Field = Backbone.Model.extend({
        options: new app.Collections.Options()
    });

    app.Collections.Fields = Backbone.Collection.extend({
        model: app.Models.Field
    });

    app.Models.Form = Backbone.Model.extend({
        formid  : "1",
        fields: new app.Collections.Fields(),
        initialize: function() {
        }
    });

How do I split up my JSON response into all these models and collections? (Perhaps I should re-evaluate my approach, and go for something like form.fieldList and form.optionList[fieldListId] instead. If so, how would that look like?)

Edit: Here is a little jsfiddle after many fixes, but I still don't really know how to make the inner options list work.


Solution

  • The easiest solution would be using Backbone Relational or Backbone Associations.

    The documentation should be enough to help you get started.

    If you don't want to use a library you could override the parse function on the Form model.

    app.Models.Form = Backbone.Model.extend({
        defaults: {
            fields: new app.Collections.Fields()
        },
    
        parse: function(response, options) {
            return {
                formid: response.formid,
                fields: new app.Collections.Fields(_.map(response.fields, function(field) {
                    if (field.options) {
                        field.options = new app.Collections.Options(field.options);
                    }
    
                    return field;
                }))
            };
        }
    });
    

    Now if you fetch a form from the server, the response will be parsed into an object graph of models and collections.

    form.get('fields') will return an app.Collections.Fields collection. form.get('fields').first().get('options') will return an app.Collections.Options collection, if any options exist.

    Also, you could create the form model like this:

    var form = new app.Models.Form(JSONresponse, {
        parse: true
    });
    

    This would result in the same object structure.