14

I'm trying to fetch a collection from my server. I'm using version 0.3.3 (not the master from github) However I am running in this exception:

Uncaught TypeError: Cannot use 'in' operator to search for 'id' in {id=MyId, active=true}
    jQuery.jQuery.extend._Deferred.deferred.resolveWith (jquery.js:869)
    done (jquery.js:6591)
    jQuery.ajaxTransport.send.callback

This is the way I created the error:

var MyModel = Backbone.Model.extend();
var MyCollection = Backbone.Collection.extend({
    url: '/api/collection',
    model: MyModel
});
var coll = new MyCollection();
coll.fetch();

The elements in /api/collection are parsed in JSON. I tried to return them in various formats

["Id1", "Id2", ... ]
[{id: "Id1, somethingElse: "..."}, ...]
{id1: { id1s content}, id2: { ... }, ...}

However the error was always the same. What is wrong with this code?

[Edit] It doesn't help to set an error via coll.fetch({error: errorFunc}); The Exception stays the same.

[Edit2] Well it seems everything works fine until collection.fetch() calls collection.refresh() with the response object. I have not overwritten any of these functions.

[Edit3] The error is in the collection.add() method and the reason is that my elements are a list of strings... My server sent them wrong.

  • You say your server sent them wrong; how do you send 'em now so it works? Might be helpful for others (like me) – Ariejan Apr 19 '11 at 14:12
  • instead of ["id1", "id2", ..., "idn"] the client expects [{"id": "id1"}, ... {"id": "idn"}] –  Jul 02 '11 at 13:03
  • I'm literally echo-ing out '[{"id":"100"}]' from my server to test it out...however, it still gives the same error...what's the echo part of yours like? – William Sham Aug 19 '11 at 21:25

2 Answers2

23

Since you already identified that your response format is not what Backbone expect, you should override YourModel.parse function that should take the response from your server and return an array of models acceptable by the collection. Here is the snippet from Backbone.js

// **parse** converts a response into a list of models to be added to the
// collection. The default implementation is just to pass it through.
parse : function(resp) {
  return resp;
},

As you can see the default function just passes data through. You would have to make it work for your response format.

P.S. id recommend placing a breakpoint in Backbone.fetch method to see what format comes from the server and where exactly it breaks the model creation.

Vlad Gurovich
  • 8,463
  • 2
  • 27
  • 28
  • 1
    Backbone expects a key "id" for each record (you can redefine the unique identifier key in your model by redeclaring idAttribute). Then the fetch from collection expects a [] json array. – Julien Mar 31 '11 at 20:35
  • Well, the "id" attribute is only used to determine whether or not the model is a new model or an existing one(meaning upon saving, do we need to create or update it?). The error that happens here, happens upon fetching the models from the server, so I beleive the problem is either bad response format that doesnt get parsed by JSON into an object properly or its simply not in a format that Backbone expects and thus needs to be polished in the "parse" function – Vlad Gurovich Mar 31 '11 at 20:53
20

instead of

["id1", "id2", ..., "idn"]

the client expects

[{"id": "id1"}, ... {"id": "idn"}]
  • This thing always confuses me about JSON :( What format should we choose. Not saying that JSON is bad, I might need to read up a bit – DivinesLight Nov 27 '11 at 20:26
  • well, i am also stuck in same kind of problem. And in my situation the server is giving me json in format same as you have prescribed here... I still got the same error, can you help please... here is the error and data: Uncaught TypeError: Cannot use 'in' operator to search for 'length' in [{"UserId":1,"Login":"test","isSelected":true},{"UserId":2,"Login":"afdsafdsf","isSelected":true},{"UserId":61,"Login":"werewrewman","isSelected":false},{"UserId":62,"Login":"ghfgu","isSelected":false},.....]... will really appreciate your help.. thanks. – Asad Malik Dec 22 '11 at 16:02
  • The reason the JSON needs to be in that format is because that's what Backbone has been designed to look for. Each Model has an `id` attribute [see the documentation for Model.id](http://backbonejs.org/#Model-id). Backbone is trying to create a collection of models from an array of text strings - that won't work because a model is so much more than a single text string. But if you pass an array of objects with the `id` attribute set to a string, Backbone can extend each Model object with each respective object in the array, thus setting each Model's `id` to the text string. – clayzermk1 Nov 09 '12 at 18:47