Artinkl
Artinkl

Reputation: 43

My model ids collide with cids ( eg: "c7" )

I am new to backbone.

After much confusion about not being able to add some of my models to a collection and sometimes getting the wrong model using collection.get(id) I found out that my model ids are colliding with backbones cids.

My model ids are something like "c7" or "c5e6". While the later is no problem "c7" is backbones own cid for the seventh element of the collection.

So if I ask for collection.get('c7') and expect null I instead get the element that was given the cid "c7" by backbone. And if I add an element with id "c7" I will never get it back with get("c7").

I wonder if I am the first one with this problem, I did not find anything about a syntax restriction of backbone ids, is there a way to solve this? As a workaround I will save my own ids in a custom attribute, and have to use collection.where instead of collection.get.

Any better ideas?

Upvotes: 3

Views: 144

Answers (2)

Kevin Peel
Kevin Peel

Reputation: 4090

Unfortunately, this does look like an edge case problem with no real solution. Looking at the Backbone source, we can see in the Backbone.Collection.set method that Backbone mixes both your IDs and their internal CIDs in the same object:

set: function(models, options) {
  // ...
  this._byId[model.cid] = model;
  if (model.id != null) this._byId[model.id] = model;
  // ...
  return this;
},

The _byId object holds all IDs which causes your issue. Here is the Backbone.Collection.get method:

get: function(obj) {
  if (obj == null) return void 0;
  return this._byId[obj.id != null ? obj.id : obj.cid || obj];
},

When you call it using a non-existent ID (of your own) like "c7", the return ... line becomes return this._byId["c7"];. Since _byId has references to yours and Backbone's IDs, you're getting their entry returned when you expected null.

nikoshr has a great solution in the answer below.

Upvotes: 2

nikoshr
nikoshr

Reputation: 33364

If you look at Backbone source code, you will see that the cid in a model is determined in the constructor by

this.cid = _.uniqueId('c');

c is an arbitrary prefix which means you could disambiguate your ids by overriding _.uniqueId, something like

_._uniqueId = _.uniqueId;
_.uniqueId = function(prefix) {
    if (prefix === 'c') {
        prefix = 'cc';
    }
    return _._uniqueId(prefix);
};

Without the override : http://jsfiddle.net/nikoshr/KmNSr/ and with it : http://jsfiddle.net/nikoshr/KmNSr/1/

Upvotes: 3

Related Questions