1

I´m new to Backbone.js, but after some research I still couldn´t find the source of my problem.

I am developing an App and I have a collection of models, which I eventually want to display in a view (just one model at a time).

Here´s my code so far:

    var App = {
        Item: Backbone.Model.extend({
            defaults: function() {
                return {
                    id: -1,
                    name: '',
                    imageReference: '',
                    itemTags: []
                };
            },
            sync: function()  { return null; },
            fetch: function() { return null; },
            save: function()  { return null; }
        }),
        Items: Backbone.Collection.extend({
            model: this.Item,
        }),
        ItemView: Backbone.View.extend({
            el: "#itemdiv",
            tagName: "<div>",
            className: "item",
            template: _.template($("#template-item-view").html()),
            initialize: function(model) {
                this.model = model;
                this.listenTo(this.model, "change", this.render);
                this.render();
            },
            render: function() {
                this.$el.html(this.template(this.model.toJSON()));
                return this;
            },
        })
    };
    var items = new App.Items();
    items.add(new App.Item({name: "iPhone", id: 1, imageReference: "iPhone.jpg", ["mobile", "smartphone"]}));
    items.add(new App.Item({name: "MacBook", id: 2, imageReference: "MacBook.jpg", ["laptop", "computer"]}));

All of the above works. When I inspect items it has the two models including the parameters. But when I try to add a new item directly to the Collection with Collection.create() like:

    items.create({name: "Apple Watch", id: 3, imageReference: "AppleWatch.jpg", ["watch", "redundant"]});

it throws an error:

TypeError: undefined is not a constructor (evaluating 'new this.model(attrs, options)')

In case it helps, this error appears in Backbone.js in line 915 (dev version), the wrapping function is

/* from Backbone.js, Dev-Version, Line 911-919 */
_prepareModel: function(attrs, options) {
  if (attrs instanceof Model) return attrs;
  options = options ? _.clone(options) : {};
  options.collection = this;
  var model = new this.model(attrs, options);
  if (!model.validationError) return model;
  this.trigger('invalid', this, model.validationError, options);
  return false;
}

I can´t figure out if that is just a small bug or if something with my architecture is wrong. Am very thankful for help and also on comments towards best practices, etc.

Thanks in advance!

  • 1
    Without digging too deeply, I think the line `model: this.Item` might be the issue. Can you take the code out of the App object and test it? – Adrian Lynch Apr 08 '15 at 10:59
  • You´re a genius, Adrian! When I add `var Items = Backbone.Collection.extend({ model: App.Item, });` outside the App-Object the `Collection.create` works. But what´s wrong with that line? How can I fix it and still leave it in the App-Object? – Vincens von Bibra Apr 08 '15 at 11:14
  • If I put `Backbone.Collection.extend({ model: App.Item, });` back into the App-Object, it says `TypeError: undefined is not an object (evaluating 'App.Item')` – Vincens von Bibra Apr 08 '15 at 11:26
  • It's because your object definition goes something like: `obj = {field: something returned by a function, not the function itself}` – Adrian Lynch Apr 08 '15 at 11:29

1 Answers1

1

You have an error in your add lines:

items.add(new App.Item({name: "iPhone", id: 1, imageReference: "iPhone.jpg", ["mobile", "smartphone"]}));
items.add(new App.Item({name: "MacBook", id: 2, imageReference: "MacBook.jpg", ["laptop", "computer"]}));

Should be:

items.add(new App.Item({name: "iPhone", id: 1, imageReference: "iPhone.jpg", itemTags: ["mobile", "smartphone"]}));
items.add(new App.Item({name: "MacBook", id: 2, imageReference: "MacBook.jpg", itemTags: ["laptop", "computer"]}));

The field itemTags was missing. Does that fix it?

The point at which the following is run:

Items: Backbone.Collection.extend({
    model: this.Item,
}),

this isn't known.

So if you're namespacing to encapsulate your code do one of either:

var App = {}

App.item = Backbone.Model.extend({...})
App.items = Backbone.Collection.extend({...})
App.itemView = Backbone.View.extend({...})

App.items.add({})
App.items.add({})

Or:

(function() {
    var item = Backbone.Model.extend({...})
    var items = Backbone.Collection.extend({...})
    var itemView = Backbone.View.extend({...})

    var items.add({})
    var items.add({})
})()
Adrian Lynch
  • 8,237
  • 2
  • 32
  • 40