Parse data of a hasMany relationship by its associated collection #453

Open
thomaswolf opened this Issue Apr 12, 2014 · 2 comments

Comments

Projects
None yet
3 participants

It would be great if models in a hasMany relationship could be parsed by the corresponding collection model. Here is an example:

var MyModel = Backbone.Model.extend({
 relations : [
  type: Backbone.HasMany,
  key : 'hasManyRelation',
  relatedModel : 'MyModel',
  collectionType : 'MyModelCollection',
  parseCollection : true // <--- unfortunately this does not exist
 ],...
});
...
var MyModelCollection = Backbone.Collection.extend({
 parse: function (resp) {
  this.metadata = resp.metadata;
  return resp.items;
 },
)}

The data returned by the server:

{
 metadata : { ... }
 items : {
  id : 1,
  attribute : "123",
  hasManyRelation : {
    metadata : { ... }
    items : [...]
   }
 }
}

I'm having the same issue. My use case is that my collections return data as paged collections. The actual array is a "data" property of the returned data.

The response for the object with a collection of children looks like:

{ 
  /* model properties */
  "children":
  {
    "paged": false, 
    "rowCount": null,
    "hasMore": false,
    "maxRows": null, 
    "offset": 0,
    "data": [ /* models are here */ ]
  }
}

My collection has a parse method:

          parse: function(response)
          {
            if (response["data"] != null)
            {
              var t = this;
              $.each(["offset", "maxRows", "hasMore", "paged"],
                function(i, prop)
                {
                  t[prop] = response[prop];
                });

              this._loadedPages[Math.floor(this.offset / this.maxRows)] = true;

              if (this.hasMore == false && Number.isInteger(this.rowCount) == false &&
                response.data.length)
              {
                this.rowCount = this.offset + response.data.length;
              }
              else if (Number.isInteger(response["rowCount"]))
              {
                this.rowCount = response.rowCount;
              }

              return response["data"];
            }

            return response;
          },

The problem is that when this collection is loaded as a relation, the parse method is never called. In this use case I don't care about having parse called on the model, I only need it called on the collection.

Found a work-around for those that may want it.

In your model (not the collection), implement a parse method:

      parse: function(response, options)
      {
        var children = response.children;
        if (children && children.data)
        {
          collection = new CustomCollection();
          items = collection.parse(children);
          collection.reset(items, { silent: true });
          response.children = collection;
        }

        return response;
      },

The backbone-relational code already checks to see if the items are a Backbone collection before parsing them in fetchRelated, so by pre-parsing them it avoids the issue.

Not pretty but it does work around the issue.

bpatram added the bug label Mar 22, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment