Mapping JSON to backbone.js collections - javascript

Alright, it looks like I need a hint to point me in the right direction. This question is two part - working with mult-dimensional JSON and Collections of Collections from JSON.
Background
I have some JSON that is going to be retrieved from a server and have control over how it could be formatted.
Multi-Dimentional JSON
I'm having some trouble being able connecting the model to the parts in the JSON. Say I wanted to render just each of the posts author name, and the content of status in the sample JSON below. I'm having no problem getting the status into the model, but the author name I'm a bit confused how to get to it. From my understanding I have to override the parse.
Is this bad standards / is there a better JSON structure I should use? Would it be better to keep it as flat as possible? That is move the author name and photo up one level?
I was reading How to build a Collection/Model from nested JSON with Backbone.js but it is still a little unclear to me.
Collection in Collections
Is there a nice way to make a collection within a collection for backbone.js? I will have a collection of posts, and then would have a collection of comments on that post. As I'm developing in backbone is that even possible?
From what I understand in Backbone.js Collection of Collections and Backbone.js Collection of Collections Issue, it would look something like this?
var Comments = Backbone.Model.extend({
defaults : {
_id : "",
text : "",
author : ""
}
})
var CommentsCollection = Backbone.Collection.extend({ model : Comments })
var Posts = Backbone.Model.extend({
defaults : {
_id : "",
author : "",
status : "",
comments : new CommentsCollection
}
})
var PostsCollection = Backbone.Collection.extend({ model : Posts })
Sample JSON
{
"posts" : [
{
"_id": "50f5f5d4014e045f000002",
"author": {
"name" : "Chris Crawford",
"photo" : "http://example.com/photo.jpg"
},
"status": "This is a sample message.",
"comments": [
{
"_id": "5160eacbe4b020ec56a46844",
"text": "This is the content of the comment.",
"author": "Bob Hope"
},
{
"_id": "5160eacbe4b020ec56a46845",
"text": "This is the content of the comment.",
"author": "Bob Hope"
},
{
...
}
]
},
{
"_id": "50f5f5d4014e045f000003",
"author": {
"name" : "Chris Crawford",
"photo" : "http://example.com/photo.jpg"
},
"status": "This is another sample message.",
"comments": [
{
"_id": "5160eacbe4b020ec56a46846",
"text": "This is the content of the comment.",
"author": "Bob Hope"
},
{
"_id": "5160eacbe4b020ec56a46847",
"text": "This is the content of the comment.",
"author": "Bob Hope"
},
{
...
}
]
},
{
...
}
]}
I appreciate even any hints to guild me. Thanks!

It can be overwhelming when trying to write up code to make it work for nested objects. But to make it simpler lets break it up into smaller manageable pieces.
I would think in these lines.
Collections
Posts
Comments
Models
Post
Comment
Author
Main collection -- Posts collection
(Which contains list of Post Models)
And each model in the Posts collection will have 3 sets of attributes(May not be the right term).
1st - level of attributes (status , id).
2nd - Author attribute which can be placed in a separate Model(Authod Model).
3rd - Collection of comments for each Post Model.
Collection in Collections would be a bit confusing here.
As you would have Models in Collection(Post Model inside Posts Collection) and each Model will nest a collection again(Comments collection inside Post Model). Basically you would be Handling a Collection inside a Model.
From my understanding I have to override the parse.
Is this bad standards / is there a better JSON structure I should use?
It is a perfectly plausible solution to handle the processing this in the Parse method. When you initialize a Collection or a Model , Parse methods is first called and then initialize is called. So it is perfectly logical to handle the logic inside the Parse method and it is not at all a bad standard.
Would it be better to keep it as flat as possible?
I don't think it is a good idea to keep this flat at a single level, as the other data is not required on the first level in the first place.
So the way I would approach this problem is write up the parse method in the Post Model which processes the response and attach the Author model and Comments collection directly on the Model instead as an attribute on the Model to keep the attributes hash clean consisting of 1st level of Post data. This I feel will be cleaner and lot more scalable on the long run.
var postsObject = [{
"_id": "50f5f5d4014e045f000002",
"author": {
"name": "Chris Crawford",
"photo": "http://example.com/photo.jpg"
},
"status": "This is a sample message.",
"comments": [{
"_id": "5160eacbe4b020ec56a46844",
"text": "This is the content of the comment.",
"author": "Bob Hope"
}, {
"_id": "5160eacbe4b020ec56a46845",
"text": "This is the content of the comment.",
"author": "Bob Hope"
}]
}, {
"_id": "50f5f5d4014e045f000003",
"author": {
"name": "Brown Robert",
"photo": "http://example.com/photo.jpg"
},
"status": "This is another sample message.",
"comments": [{
"_id": "5160eacbe4b020ec56a46846",
"text": "This is the content of the comment.",
"author": "Bob Hope"
}, {
"_id": "5160eacbe4b020ec56a46847",
"text": "This is the content of the comment.",
"author": "Bob Hope"
}]
}];
// Comment Model
var Comment = Backbone.Model.extend({
idAttribute: '_id',
defaults: {
text: "",
author: ""
}
});
// Comments collection
var Comments = Backbone.Collection.extend({
model: Comment
});
// Author Model
var Author = Backbone.Model.extend({
defaults: {
text: "",
author: ""
}
});
// Post Model
var Post = Backbone.Model.extend({
idAttribute: '_id',
defaults: {
author: "",
status: ""
},
parse: function (resp) {
// Create a Author model on the Post Model
this.author = new Author(resp.author || null, {
parse: true
});
// Delete from the response object as the data is
// alredy available on the model
delete resp.author;
// Create a comments objecton model
// that will hold the comments collection
this.comments = new Comments(resp.comments || null, {
parse: true
});
// Delete from the response object as the data is
// alredy available on the model
delete resp.comments;
// return the response object
return resp;
}
})
// Posts Collection
var Posts = Backbone.Collection.extend({
model: Post
});
var PostsListView = Backbone.View.extend({
el: "#container",
renderPostView: function(post) {
// Create a new postView
var postView = new PostView({
model : post
});
// Append it to the container
this.$el.append(postView.el);
postView.render();
},
render: function () {
var thisView = this;
// Iterate over each post Model
_.each(this.collection.models, function (post) {
// Call the renderPostView method
thisView.renderPostView(post);
});
}
});
var PostView = Backbone.View.extend({
className: "post",
template: _.template($("#post-template").html()),
renderComments: function() {
var commentsListView = new CommentsListView({
// Comments collection on the Post Model
collection : this.model.comments,
// Pass the container to which it is to be appended
el : $('.comments', this.$el)
});
commentsListView.render();
},
render: function () {
this.$el.empty();
// Extend the object toi contain both Post attributes
// and also the author attributes
this.$el.append(this.template(_.extend(this.model.toJSON(),
this.model.author.toJSON()
)));
// Render the comments for each Post
this.renderComments();
}
});
var CommentsListView = Backbone.View.extend({
renderCommentView: function(comment) {
// Create a new CommentView
var commentView = new CommentView({
model : comment
});
// Append it to the comments ul that is part
// of the view
this.$el.append(commentView.el);
commentView.render();
},
render: function () {
var thisView = this;
// Iterate over each Comment Model
_.each(this.collection.models, function (comment) {
// Call the renderCommentView method
thisView.renderCommentView(comment);
});
}
});
var CommentView = Backbone.View.extend({
tagName: "li",
className: "comment",
template: _.template($("#comment-template").html()),
render: function () {
this.$el.empty();
this.$el.append(this.template(this.model.toJSON()));
}
});
// Create a posts collection
var posts = new Posts(postsObject, {parse: true});
// Pass it to the PostsListView
var postsListView = new PostsListView({
collection: posts
});
// Render the view
postsListView.render();
Check Fiddle

(Edited to correct my initial misreading of the question.)
There's no need to override parse method of the model unless you want to change its structure. But it sounds like you don't need to -- to render the author name, just use author.name in the view:
<%= author.name %>
As far as initializing the nested collection, your approach is exactly right. All you have to do is convert the JSON object to Backbone models, and pass them to the PostsCollection (the Backbone.Collection constructor accepts an array of Backbone models, not raw JSON). One way of doing this is to use map:
var postModels = json.posts.map(function(post) { return new Posts(post); });
var posts = new PostsCollection(postModels);
Note that you'll need to do something similar in the initialize method of the Posts model -- retrieve the comments JSON array, and convert it to an array of Comments models:
initialize: function() {
if (attributes.comments && attributes.comments.length > 0) {
var commentModels = attributes.comments.map(function(comment) {
return new Comments(comment);
});
this.set("comments", new CommentsCollection(commentModels));
}
}
Here is working example.

Update, I found a SuperModel for backbone which provides relationships between models and between collections. It has proved to be a great solution for Collections within Collections as well as Deep Nested Model data.
Models are pre-defined with their relationships to other models via key. During the initialize/parse of the model any values in the JSON at that key gets passed off to a new related model or collection. A relationship is created between the two models/collections.
This means with the above example we can do something like this with our models:
Setup
var Author = Supermodel.Model.extend({});
var Post = Supermodel.Model.extend({});
var Comment = Supermodel.Model.extend({});
var Posts = Backbone.Collection.extend({
model: function(attrs, options) {
return Post.create(attrs, options);
}
});
var Comments = Backbone.Collection.extend({
model: function(attrs, options) {
return Comment.create(attrs, options);
}
});
Post.has().one('author', {
model: Author,
inverse: 'post'
}).many('comments', {
collection: Comments,
inverse: 'post'
});
//reverse relationships could also be setup
Usage
var posts = new Posts( postsObject ); //where postsObject is an array of posts
//With SuperModel, we are able to navigate the related models
posts.first().comments();
posts.first().comments().author();
posts.last().author();
Fiddle
Working Example in JSFiddle

Related

Backbone Menu Not Sorting

I'm having trouble getting a Backbone collection to sort properly. I inherited the project, so there may be some shenanigans someplace else, but I want to rule out any syntax error on my part.
The project uses a JSON file to handle the data:
"classifications": [
{
"name": "1 Bedroom",
"alias": "1BR",
"id": "1BR",
"menu_desc": "Residences"
},
{
"name": "2 Bedroom",
"alias": "2BR",
"id": "2BR",
"menu_desc": "Residences"
},
{
"name": "3 Bedroom",
"alias": "3BR",
"id": "3BR",
"menu_desc": "Residences"
},
{
"name": "4 Bedroom",
"alias": "4BR",
"id": "4BR",
"menu_desc": "Residences"
},
{
"name": "Common Areas",
"alias": "Common",
"id": "Common",
"menu_desc": "Resident Amenities"
}
]
Previously, there were no one-bedroom units, and the order in which it rendered was this:
I added the one-bedroom classification, and suddenly the order was this:
I did some digging and found documentation about the comparator property, but it only seems to apply to collections. This project doesn't use a collection for the classifications. It does for the submenu items (which floor the units are on, etc.), but not the main menu:
var MenuClassificationListView = Backbone.View.extend({
id: "classification_accordion",
template: _.template( "<% var classifications = this.options.classifications; _.each(this.collection.attributes, function(v,k) { %>"+
"<h3 class='<%= k %>'><%= classifications.get(k).get('name') %>"+
"<p><%=classifications.get(k).get('menu_desc')%></p></h3>"+
"<% var model = new MenuClassificationList(v); var view = new MenuClassificationItemView({collection:model, classification:k}); %>"+
"<% print(view.render().el.outerHTML); %>"+
"<% }); "+
"%>"),
render: function(){
//console.log(this.options.classifications);
//console.log(this.collection.attributes);
//alert(1);
this.$el.html(this.template());
return this;
}
});
How do I incorporate the comparator?
Thanks,
ty
One way could be to define a collection for the classifications, same way they are defined for the other items you mention:
var Classifications = Backbone.Collections.extend({ // etc. etc.
That way you can add the comparator and it will always be sorted.
Another way is to sort (http://underscorejs.org/#sortBy) the array in the initialize function in your view:
initialize: function(options) { // sorry don't remember the exact syntax for the parameters passed in, but I believe options is what you need
this.options.sortedclassifications = _sortBy(options.classifications, function (c) { return parseInt(c.id); }); // or any other sorting logic
}
Then in the template use the sorted classifications:
template: _.template( "<% var classifications = this.options.sortedclassifications; _.each(this.collection.attributes, function(v,k) { %>" + // etc. etc.
This should give you what you need. However, if I may add a personal opinion, I would go through the effort of defining a Collection for the classifications and a model for the single classification. Moreover, I would keep the MenuClassificationListView but also create a MenuClassificationView that will hold the single classification template.
In this way you are able to compose views, change rendering of the single classification without changing the list and scope the events to the inner views (so clicking on a single classification is handled by the single classification view). It makes everything cleaner, more composable and readable, in my opinion.
_.sortBy does not need to be used as Backbone collections already come with built in functionality for sorting.
See: http://backbonejs.org/#Collection-comparator
Example:
var SortedCollection = Backbone.Collection.extend({
comparator: 'key'
});
var mySortedCollection = new SortedCollection([{a:5, key:2}, {key:1}]);
console.log( mySortedCollection.toJSON() );
// [{key:1}, {a:5, key:2}]
However, the collection will not be automatically re-sorted when changing the key attribute. See:
mySortedCollection.at(0).set( 'key', 3 );
console.log( mySortedCollection.toJSON() );
// [{key:3}, {a:5, key:2}]
You have multiple options to solve this problem: you can manually call mySortedCollection.sort() or you can initialize the collection by binding its change:key event to re-sort the collection. The change:key event is triggered by the model whose key attribute is changed. This event is automatically propagated to the collection.
var AutoSortedCollection = Backbone.Collection.extend({
comparator: 'key',
initialize: function() {
this.listenTo( this, 'change:key', this.sort );
}
});
In addition, I suggest removing functionality from the templates. It is easy to debug Backbone Views, but it gets harder to read the stack trace as you move functionality inside the template string. You also enforce proper separation of concerns by using your Backbone View for preparing all data for presentation and your template should just display it.
var MyView = Backbone.View.extend({
//...
serializeData: function() {
return {
classifications: this.collection.toJSON(),
keys: this.collection.length > 0 ? this.collection.at(0).keys() : []
}; // already sorted
}
render: function() {
this.$el.html(this.template( this.serializeData() ));
}
});
Your template string becomes much easier to read: you can directly use the variables classifications and keys, iterate on them with _.each and simply reference to values without having to deal with the Collection syntax.

Viewing in backbone data from RESTful service

I am trying to view the collection i import from the service, using backbone on the client side, and python/flask as the service. When i make the GET request, i get the following data back:
{"entries": [{"Title": "my title 1", "Description": "My desc 1", "Info": "Info 1", "ids": 1}, {"Title": "my title 2", "Description": "My desc 2", "Info": "Info 2", "ids": 2}]}
But those entries are not showing on my page, even though i use fetch. This is my ListView code:
var app = app || {};
app.ContactListView = Backbone.View.extend({
el: '#contacts',
initialize: function () {
this.collection = new app.ContactList();
this.collection.fetch({reset: true});
this.render();
this.listenTo( this.collection, 'reset', this.render );
},
render: function () {
this.collection.each(function( item ){
this.renderContact( item );
}, this );
},
renderContact: function ( item ) {
var contactView = new app.ContactView({
model: item
});
this.$('#ContactTable').append( contactView.render().el );
}
});
What might be the cause?
The reason is because your collection is expecting an array of models as it's response but your service is returning the array under entries. From the documentation
parse is called by Backbone whenever a collection's models are
returned by the server, in fetch. The function is passed the raw
response object, and should return the array of model attributes to be
added to the collection.
To work around that you can simply override your parse method to return the array of models.
For example:
app.ContactList = Backbone.Collection.extend({
//...
parse: function (response) {
return response.entries;
}
})

Ember js - Hasmany relationships breaks after updating other tables

I am using Ember.js with local-storage-adapter. I have a weird problem while updating records.
I have a post and comments model with hasMany relationships:
App.Post = DS.Model.extend({
title: DS.attr('string'),
comments: DS.hasMany('comment', {
async: true
})
});
App.Comment = DS.Model.extend({
message: DS.attr('string')
});
These are my post and comments controllers:
App.PostsController = Ember.ArrayController.extend({
newTitle: '',
actions: {
create: function() {
var title = this.get('newTitle');
var post = this.store.createRecord('post', {
title: title
});
this.set('newTitle', '');
post.save();
}
}
});
App.CommentsController = Ember.ArrayController.extend({
needs: "post",
post: Ember.computed.alias("controllers.post.model"),
newMessage: '',
actions: {
create: function() {
var message = this.get('newMessage');
var comment = this.store.createRecord('comment', {
message: message
});
var post = this.get('post');
var comments = post.get('comments');
if (comments.get('content') == null) comments.set('content', []);
comments.pushObject(comment);
comment.save();
post.save();
}
}
});
While creating records hasMany relations updated correctly.
{
"App.Post": {
"records": {
"0v66j": {
"id": "0v66j",
"title": "post1",
"comments": ["p31al", "tgjtj"]
}
}
},
"App.Comment": {
"records": {
"p31al": {
"id": "p31al",
"message": "comment 1"
},
"tgjtj": {
"id": "tgjtj",
"message": "comment 2"
}
}
}
}
The problem occured while editing post. The relationships are gone after editing the post record. I did some searching and found this code:
DS.JSONSerializer.reopen({
serializeHasMany: function(record, json, relationship) {
var key = relationship.key;
var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
// alert(relationshipType);
if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany' || relationshipType === 'manyToOne') {
json[key] = Ember.get(record, key).mapBy('id');
// TODO support for polymorphic manyToNone and manyToMany
// relationships
}
}
});
This did the trick and it worked fine. But now I have another problem. If I edit any other record, all the id references are replaced by whole object like this:
{"App.Post":{"records":{"0v66j":{"id":"0v66j","title":"post2","comments":[**{"message":"comment 1"},
{"message":"comment 2"}**]},"8nihs":{"id":"8nihs","title":"post3","comments":["b4v2b","dbki4"]}}},
"App.Comment":{"records":{"p31al":{"id":"p31al","message":"comment 1"},"tgjtj":{"id":"tgjtj","message":"comment 2"},
"b4v2b":{"id":"b4v2b","message":"comments3"},"dbki4":{"id":"dbki4",
"message":"comments4"}}}}
Comment refrences should be comments":["p31al","tgjtj"] like this. but the ids are replaced as "comments":[{"message":"comment 1"},{"message":"comment 2"}]
When using ApplicationSerializer which extends LSSerializer, it seems to work.
Maybe it got fixed since asked?
I've noticed a few things in my path with Ember... and especially Ember-Data.
One of them is when dealing with associations I've had to manually re-add in the associations saving and having to re-save, and use addObject to in-memory associations as you're using a bit here. :)
Note that this usually only happens when I'm updating more than one new object at once. For example, if your post is new, and your comment is also new.
I'm a little worried to see the following code in your codebase, because it shouldn't need to be there. You shouldn't ever have null or non-array objects in your associations. I'm not sure what hackery you did with the Adapter and why it was necessary, but I hope that wasn't the reason:
if(comments.get('content') == null)
comments.set('content', []);
Anyway, the following code is how I would probably write your create action. It might help. I hope it does.
create: function() {
// get the post for association on the new comment
var post = this.get('post');
// get the message to store on the new comment
var message = this.get('newMessage');
var comment = this.store.createRecord('comment', {
message : message,
post : post
});
comment.save().then(function(savedComment) {
post.get('comments').addObject(savedComment);
});
}
Note that it's a lot simpler. Generally if you're doing tricky complicated things, something's amiss and it's time to go back to basics and add one thing at a time, testing thoroughly between additions. :)
Good luck!

Backbone-Relational related models not being created

I'm trying to create a nested, relational backbone project but I'm really struggling. The rough idea of what I'm trying to do is shown below but I was under the impression upon calling fetch() on Client, a number of bookings would automatically be created based on the bookings being returned as JSON.
The format of my JSON can be seen beneath the outline of the MVC:
/****************************************************
/* CLIENT MODEL - Logically the top of the tree
/* has a BookingsCollection containing numerous Booking(s)
/* Client
/* -Bookings [BookingsCollection]
/* -Booking [Booking]
/* -Booking [Booking]
/*****************************************************/
var Client = Backbone.RelationalModel.extend({
urlRoot: '/URL-THAT-RETURNS-JSON/',
relations: [
{
type: Backbone.HasMany,
key: 'Booking',
relatedModel: 'Booking',
collectionType: 'BookingsCollection'
}
],
parse: function (response) {
},
initialize: function (options) {
console.log(this, 'Initialized');
}
});
var Booking = Backbone.RelationalModel.extend({
initialize: function (options) {
console.log(this, 'Initialized');
}
});
var BookingsCollection = Backbone.Collection.extend({
model: Booking
});
Any help outlining what I'm doing wrong would be massively appreciated.
Thanks
EDIT
Thanks for taking the time to post the feedback, it's exactly what I was hoping for.
Is it the case that the JSON physically defines the actual attributes of models if you don't go to the effort of setting attributes manually?
In other words, if the JSON I get back is as you have suggested above, would Backbone simply create a Client object (with the 4 attributes id, title, firstname & surname) as well as 2 Booking objects (each with 4 attributes and presumably each members of the BookingsCollection)?
If this is the case, what is the format for referencing the attributes of each object? When I set up a non-backbone-relational mini-app, I ended up in a situation whereby I could just reference the attributes using Client.Attribute or Booking[0].EventDate for example. I don't seem to be able to do this with the format you have outlined above.
Thanks again.
The JSON being returned is not what Backbone or Backbone-Relational is expecting by default.
The expectation of Backbone and Backbone-Relational is:
{
"id": "123456",
"Title":"Mr",
"FirstName":"Joe",
"Surname":"Bloggs",
"Bookings": [
{
"id": "585462542",
"EventName": "Bla",
"Location":"Dee Bla",
"EventDate":"November 1, 2012"
},
{
"id": "585462543",
"EventName": "Bla",
"Location":"Dee Bla",
"EventDate":"November 1, 2012"
}
]
}
To use your response, you need to create a parse function on the Client model that returns the structure I've posted above.
A jsFiddle example of your model definitions working with my example JSON: http://jsfiddle.net/edwardmsmith/jVJHq/4/
Other notes
Backbone expects ID fields to be named "id" by default. To use another field as the ID for a model, use Model.idAttribute
The "key" for the Bookings Collection I changed to "Bookings"
Sample Code:
Client = Backbone.RelationalModel.extend({
urlRoot: '/URL-THAT-RETURNS-JSON/',
relations: [
{
type: Backbone.HasMany,
key: 'Bookings',
relatedModel: 'Booking',
collectionType: 'BookingsCollection'
}
],
parse: function (response) {
},
initialize: function (options) {
console.log(this, 'Initialized');
}
});
Booking = Backbone.RelationalModel.extend({
initialize: function (options) {
console.log(this, 'Initialized');
}
});
BookingsCollection = Backbone.Collection.extend({
model: Booking
});
myClient = new Client( {
"id": "123456",
"Title":"Mr",
"FirstName":"Joe",
"Surname":"Bloggs",
"Bookings": [
{
"id": "585462542",
"EventName": "Bla",
"Location":"Dee Bla",
"EventDate":"November 1, 2012"
},
{
"id": "585462543",
"EventName": "Bla",
"Location":"Dee Bla",
"EventDate":"November 1, 2012"
}
]
});
console.log(myClient);​
Post Edit
Yes, the JSON pretty much defines the attributes of the model. You can use a combination of parse(), defaults, and validate() to better control what attributes are valid and allowed.
The canonical way of reading and setting properties on a Backbone Model is through the get(), escape(), and set() functions.
set is especially important as this does a bunch of housekeeping, such as validating the attribute and value against your validate function (if any), and triggering change events for the model that your views would be listening for.
In the specific case of the situation in this answer, you might
myClient.get('Title'); // => "Mr"
myClient.get('Bookings'); //=> an instance of a BookingsCollection with 2 models.
myClient.get('Bookings').first().get('Location'); //=> "Dee Bla"
myClient.get('Bookings').last().get('Location'); //=> "Dee Bla"
myClient.get('Bookings').first().set({location:"Bora Bora"});
myClient.get('Bookings').first().get('Location'); //=> "Bora Bora"
myClient.get('Bookings').last().get('Location'); //=> "Dee Bla"

Backbone.Collection.fetch throws "Object [...] has no method '_validate'"

I've got a simple Backbone collection that pulls a list of objects from a (remote) resource. Calling Collection.fetch, though, fails with this error:
Object [object Object] has no method '_validate'
I'm guessing this is happening under the hood when the collection attempts to create a model instance for each JSON object while adding. Can anyone shed some light on why this would happen?
Here's the code I'm using. Very bare bones...
/* Models */
var SomeModel = Backbone.View.extend({});
/* Collections */
var SomeCollection = Backbone.Collection.extend({
url: 'http://localhost:8000/api/some/resource/?format=json',
model: SomeModel,
parse: function(data) {
return data.objects
}
});
var SomeView = Backbone.View.extend({
collection: new SomeCollection(),
initialize: function() {
this.collection.fetch();
},
});
And here's an example of the resource response:
{
"meta": {
"count": 100
},
"objects": {
{"title": "Title", "id": 1},
{"title": "Title 2", "id": 2}
}
}
You probably didn't set your collection's model option to a valid Backbone.Model subclass. When the collection fetches the data it will instantiate models and call set, which will call _validate, which a valid Backbone.Model subclass will have, but your instances do not. See the annotated source code for Backbone.Collection.fetch for details.
Thanks for posting code. here's the problem. Your SomeModel extends View instead of Model. My guess is copy/paste/forget-to-edit.
var SomeModel = Backbone.View.extend({});

Categories

Resources