CanJS object list automatic subclassing and reclassing

217 Views Asked by At

A remote, third-party JSONP server provides my CanJS script with a list of results like this one:

[
    { "class": "ABaseClass", "value": "1"},
    { "class": "ASubClass", "value": "2"},
    { "class": "ABaseClass", "value": "3"},
    { "class": "ASubClass", "value": "4"}, 
    ...
]

where type is the intended object class, defined in CanJS using can.Model.extend:

The following simplified code demonstrates the CanJS setup:

ABaseClass = can.Model.extend({ ... }, {
    'findAll': { 'url': 'the url', 'dataType': "jsonp" }
    // this is modified source code and may not run
});

// ASubClass is a subclass of ABaseClass.
ASubClass = ABaseClass.extend({ ... }, { ... });

Problem:

When ABaseClass.findAll({}, function(data) { ... }) is called, which calls the JSONP endpoints for more objects, the callback obtains a list of CanJS models, but only of class ABaseClass.

Question:

Is there a helper method provided by CanJS to automatically create subclasses based on a field within a list of objects? If not, how can I go about implementing one?


Expected output:

[
    (new ABaseClass(...)),
    (new ASubClass(...)),
    (new ABaseClass(...)),
    (new ASubClass(...)),
    ...
]

Environment:

  • CanJS: 1.17
  • jQuery: 1.10.1
  • I cannot control what types of objects the endpoint returns.
  • Multiple AJAX calls is not an accepted solution.
1

There are 1 best solutions below

0
On

The easiest way to do this would be to override the models method and find the correct model for the class like this:

ABaseClass = can.Model.extend('ABaseClass', {
    'findAll': { url: "/the_url", dataType: "jsonp" },
    models: function(results){
        return_models = new can.List();
        can.each(results, function(result){
            return_models.push( window[result.class].model(result.value) )
        })
        return return_models;
    }
}, {});

ASubClass = ABaseClass.extend('ASubClass', {}, {});

ABaseClass.findAll({}, function(results){
    console.log(results);
})

What this does is:

  1. When the findAll returns it sends it's result to the models method.
  2. The models method then loops over each of the results.
  3. It then finds the model constructor attached to the window. ( window[result.class] )
  4. Then we call model on the constructor to construct/update the model instance.
  5. Add the model instance to a can.List and return it.

I have tested this in CanJS 2.0.x and it works fine here.

You can find more details about how this all works in the docs:

It looks like these will be Deprecated in CanJS 2.1.0 in favour of .parseModels and .parseModel