-1

Afternoon all, I'm relatively new to backbone and have been stumped for 3 days with this error which I have not seen before.

I have a collection 'TestCollection' which defines it's model as a function. When the collection is loaded I get an error the first time it attempts to make a model with class 'TestModel'.

The error I get is:

Uncaught TypeError: TestModel is not a constructor
at new model (testCollection.js:14)
at child._prepareModel (backbone.js:913)
at child.set (backbone.js:700)
at child.add (backbone.js:632)
at child.reset (backbone.js:764)
at Object.options.success (backbone.js:860)
at fire (jquery.js:3143)
at Object.fireWith [as resolveWith] (jquery.js:3255)
at done (jquery.js:9309)
at XMLHttpRequest.callback (jquery.js:9713)

I believe I have given both the collection and the model all of the code they should need to work. It feels like something has gone wrong with the loading, but when I put a console.log at the top of the model file I could see that it is definitely being loaded before the collection attempts to use it.

Any help would be massively appreciated.

TestCollection:

define([
  'backbone',
  'models/testModel'
], function(Backbone, TestModel) {

  var TestCollection = Backbone.Collection.extend({

    model: function(attrs) {
      switch (attrs._type) {
        case 'test':
          console.log('making a test model')
          return new TestModel();
      }
    },

    initialize : function(models, options){
      this.url = options.url;
      this._type = options._type;
      this.fetch({reset:true});
    }

  });

  return TestCollection;

}); 

TestModel:

require([
  './testParentModel'
], function(TestParentModel) {

  var TestModel = TestParentModel.extend({

    urlRoot: 'root/url',

    initialize: function() {
      console.log('making test model')
    }
  });

  return TestModel;
});

File where TestCollection is made:

define(function(require) {

  var MyProjectCollection = require('collections/myProjectCollection');
  var TestCollection = require('collections/testCollection');

  Origin.on('router:dashboard', function(location, subLocation, action) {



  Origin.on('dashboard:loaded', function (options) {
    switch (options.type) {
      case 'all':
        var myProjectCollection = new MyProjectCollection;

        myProjectCollection.fetch({
          success: function() {
            myProjectCollection.each(function(project) {

              this.project[project.id] = {};

              this.project[project.id].testObjects = new TestCollection([], {
                url: 'url/' + project.id,
                _type: 'test'
              });
            });
          }
        });
    }
  });

});

I've had a look around stack overflow, it does not appear to be the issue below (which seems to be the most common issue). Model is not a constructor-Backbone

I also do not think I have any circular dependencies.

Any help would be massively appreciated as I am completely stumped. I've tried to include only the relevant code, please let me know if additional code would be useful.

Thanks

Community
  • 1
  • 1
user3707803
  • 101
  • 1
  • 11
  • If I attempt to console.log(TestModel) the line above return new TestModel() in the collection then 'undefined' is returned. However I can see that the file is loaded in the network tab of the browser. What is the best way to debug this? – user3707803 May 07 '17 at 17:12
  • Here's [how to store different model types in the same collection](http://stackoverflow.com/a/40638871/1218980). – Emile Bergeron May 08 '17 at 14:30

1 Answers1

1

I can't say for other parts of the code but an obvious problem you have is misunderstanding what data is passed to the model creator function.

var TestCollection = Backbone.Collection.extend({
    model: function(attrs) {
        switch (attrs._type) { // attrs._type does exist here
            console.log( attrs ); // Will print { foo: 'bar' }

            case 'test': // This will always be false since attrs._type does not exist 
                console.log('making a test model')
                return new TestModel();

            default: 
                return new Backbone.Model(); // Or return some other model instance, 
                                             // you MUST have this function return 
                                             // some kind of a Backbone.Model
        }
    },

    initialize : function(models, options){
        this.url = options.url;
        this._type = options._type;
        this.fetch({reset:true});
    }
});

new TestCollection([ { foo: 'bar' }], {
    url: 'url/' + project.id,
    _type: 'test' // This will NOT be passed to the model attrs, these are  
                  // options used for creating the Collection instance.
})

To re-iterate. When you instantiate a Collection you pass an array of plain objects [{ foo: 'bar'}, { foo: 'baz'}] ( or you get them via fetch like you're doing ). That object will be passed as the attrs parameter in the model function, and the model function MUST return at least some kind of a Backbone.Model instance so you need a fallback for your switch statement.

Mario
  • 128
  • 7