RequireJS + BackboneRelational + Self-Referential
Asked Answered
R

2

0

I've been trying to follow the example here: Creating nested models with backboneJS + backbone-relational + requireJS

And ended up having something different (since I need a Backbone.Collection, not a Backbone.RelationalModel):

define(['exports', 'backbone', 'backbone.relational'], function (Exports, Backbone) {
    var ModuleModel = Backbone.RelationalModel.extend({
        relations : [{
                        type : Backbone.HasMany,
                        key : "children",
                        relatedModel : 'ModuleModel',
                        collectionType : 'ModuleCollection'
                     }] 
    });
    Exports.ModuleModel = ModuleModel;
    return ModuleModel;
});

define(['exports', 'backbone'], function(Exports, Backbone) {
    var ModuleCollection = Backbone.Collection.extend({
        model : Exports.ModuleModel,
    });
    Exports.ModuleCollection = ModuleCollection;
    return ModuleCollection;
});

But, when I do:

var modules = new ModuleCollection();
modules.fetch();

I get:

TypeError: this.model is undefined

And it's kind of obvious since Exports.ModuleModel is created after ModuleCollection has been initialized.

Any hints on how to achieve this self-referential model?

Thanks in advance!

Raseta answered 2/6, 2013 at 18:47 Comment(0)
R
0

Ok, I solved it by exposing the namespaces in the global scope (just removed var).

I don't know if this is AMD complaint, but at least it doesn't look that bad:

define(['backbone', 'backbone.relational'], function (Backbone) {
    ModuleModel = Backbone.RelationalModel.extend({
        relations : [{
                        type : Backbone.HasMany,
                        key : "children",
                        relatedModel : 'ModuleModel',
                        collectionType : 'ModuleCollection'
                     }] 
    });
    return ModuleModel;
});

define(['backbone', 'models/module'], function(Backbone, ModuleModel) {
    ModuleCollection = Backbone.Collection.extend({
        model : ModuleModel,
    });
    return ModuleCollection;
});

If someone has a better solution, feel free to post it!

Raseta answered 3/6, 2013 at 13:33 Comment(0)
M
1

One of the advantages of AMD is that it eliminates the need for global variables, thereby reducing the time needed to lookup object references. So yea, putting objects in the global namespace most definitely is not AMD :p

The chief problem in your original post appears to stem from a misunderstanding of RequireJS. I see three (maybe four) problems:

  1. Neither module declares a reference to the other (they only reference Backbone and Backbone-relational).
  2. exports appears to be used as a substitute for the global namespace - it isn't. You use exports to create an empty object for the module that is available immediately for reference by other modules - but you have to reference it!
  3. relatedModel and collectionType accept either object references or the names of objects accessible through global namespace. Since you're using AMD you're not defining globals, therefore you need to provide valid object references.
    • collectionType will simply point to the imported Collection object
    • relatedModel is a bit trickier. Since it's a self reference, the object it's referencing won't actually exist until the extend() operation completes, so you have to delay it's assignment until later.
  4. RequireJS requires that each file define exactly one module. I assume that the code samples above represent two separate files, but in case they don't, they should.

This should work:

ModuleModel.js:

define(['exports', 'ModuleCollection'], function (exports, Module) {
    'use strict';

    var Model = Backbone.RelationalModel.extend({
        relations : [{
            type : Backbone.HasMany,
            key : 'children',
            // `Model` undefined at this point in time, so this line is useless:
            relatedModel : Model,
            // `Collection` is attached to the imported `Module` object:
            collectionType : Module.Collection
        }]
    });

    // Now that `Model` is defined, we can supply a valid object reference:
    Model.prototype.relations[0].relatedModel = Model;

    // Attach `Model` to `exports` so an obj ref can be obtained elsewhere
    exports.Model = Model;
});

ModuleCollection.js

define(['exports', 'ModuleModel'], function(exports, Module) {
    'use strict';

    var Collection = Backbone.Collection.extend({
        // `Model` is attached to the imported `Module` object
        model : Module.Model,
        url: 'data.php' // <-- or wherever
    });

    // Attach `Collection` to `exports` so an obj ref can be obtained elsewhere
    exports.Collection = Collection;
});

Main.js

define(['ModuleCollection'], function(Module) {
    'use strict';

    var modules = new Module.Collection();
    modules.fetch();

});

Hope this helps...

Meetly answered 9/6, 2013 at 0:35 Comment(0)
R
0

Ok, I solved it by exposing the namespaces in the global scope (just removed var).

I don't know if this is AMD complaint, but at least it doesn't look that bad:

define(['backbone', 'backbone.relational'], function (Backbone) {
    ModuleModel = Backbone.RelationalModel.extend({
        relations : [{
                        type : Backbone.HasMany,
                        key : "children",
                        relatedModel : 'ModuleModel',
                        collectionType : 'ModuleCollection'
                     }] 
    });
    return ModuleModel;
});

define(['backbone', 'models/module'], function(Backbone, ModuleModel) {
    ModuleCollection = Backbone.Collection.extend({
        model : ModuleModel,
    });
    return ModuleCollection;
});

If someone has a better solution, feel free to post it!

Raseta answered 3/6, 2013 at 13:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.