Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support more than one level of inheritance for 'subModelTypes' (Polymorphic collections/HasMany) #360

Closed
jrreed opened this issue Jun 7, 2013 · 1 comment

Comments

@jrreed
Copy link
Contributor

jrreed commented Jun 7, 2013

I've run into an issue using subModelTypes for Polymorphic collections/HasMany.

Here is a jsFiddle demonstrating my issue and the fix I came up with:
http://jsfiddle.net/jimbo/HVDpQ/

My issue is that if one of the classes listed in subModelTypes is extended, and defines its own a set of subModelTypes as well, it doesn't get properly inflated from the JSON coming from the server.

So if you're using the following classes:

    window.Zoo = Backbone.RelationalModel.extend({
        relations: [{
            type: Backbone.HasMany,
            key: 'animals',
            relatedModel: 'Animal',
            collectionType: 'AnimalCollection'
        }]
    });

    window.Animal = Backbone.RelationalModel.extend({
        subModelTypes: {
            'mammal': 'Mammal'
        }
    });

    window.AnimalCollection = Backbone.Collection.extend({
        model: Animal
    });

    window.Mammal = Animal.extend({
        subModelTypes: {
            'dog': 'Dog'
        }
    });

    window.Dog = Mammal.extend();

If you then try to create a new Zoo like so:

    var zoo = new Zoo({
        animals: [{type: 'dog'}]
    });

I would expect zoo.get("animals").first() to be an instance of Dog but its actually an instance of Animal.

I did some poking around a bit and I found that the Backbone.RelationalModel.build function is only searching the subModelTypes defined in the top-level class. I'm thinking that it should probably check the subModelType attributes of its entire class hierarchy too:

Backbone.RelationalModel = Backbone.RelationalModel.extend({}, {
    build: function (attributes, options) {
        // 'build' is a possible entrypoint; it's possible no model hierarchy has been determined yet.
        this.initializeModelHierarchy();

        // Determine what type of (sub)model should be built if applicable.
        // Lookup the proper subModelType in 'this._subModels'.
        var model = this._findSubModelType(this, attributes) || this;
        return new model(attributes, options);
    },
    _findSubModelType: function (type, attributes) {
        if (type._subModels && type.prototype.subModelTypeAttribute in attributes) {
            var subModelTypeAttribute = attributes[type.prototype.subModelTypeAttribute];
            var subModelType = type._subModels[subModelTypeAttribute];
            if (subModelType) {
                return subModelType;
            } else {
                for (subModelTypeAttribute in type._subModels) {
                    return this._findSubModelType(type._subModels[subModelTypeAttribute], attributes);
                }
            }
        }
        return null;
    }
});
@jrreed
Copy link
Contributor Author

jrreed commented Jun 11, 2013

I'd be happy to put together the tests and pull-request for adding this functionality. I just need to know if this would be a welcome addition if it is the right way to go about it.

PaulUithol added a commit that referenced this issue Jul 23, 2013
Fixes #360. Adds support for deep subModelType hierarchies.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant