javascriptcanjscanjs-model

CanJS parseModels and data coercion


I think I may have an odd use case here. I've got a Code model with code, title, description attributes. Users are documenting work (healthcare), they enter the code, say 7, and 7 always means that something particular happened, say "The patient was cured." Whatever, doesn't matter. Point is, I don't want to bother saving the title and description in every model, but I want to be able to pull them for displaying.

So the API delivers an array of codes like [ 1, 13, "A4" ]. I'm trying to use both can.Model.parseModel and can.Map.define to coerce that array into Code models, but I'm having a hard time.

Why is parseModel, parseModels never called in this example? fiddle

Code = can.Model.extend({
  parseModel: function(data) {
    // return { code:data }
    console.log('Never hit!');
  },
  parseModels: function() {
    // ...
    console.log('Never hit!');
  }
},{
  _title: can.compute(function() {
    // return title from cached lookup
  })
});

Model = can.Model.extend({
  findAll: 'GET /Models'
},{
  define: {
    Codes: {
      Type: Code.List
    }
  }
});

can.fixture('GET /Models', function() {
  return [
    { Codes: [1,2,3] }, // I want to turn each number into an object
    { Codes: [4,5,6] },
    { Codes: [7,8,9] }
  ];
});

Model.findAll({});

Solution

  • .parseModels is only called during retrieval of CRUD service data.

    To make your example work, you have to make a Model.parseModel convert each Code array to an an array of objects.

    Alternately, you could change Model's define.Codes.Type to something like:

    Codes: {
      type: function(newVal){
        if(newVal instanceof Code.List) {
          return newVal
        } else {
          return new Code.List( newVal.map(function(num){ return {value: num}}) )
        }
      }
    }