How to handle custom response in Backbone model - javascript

I started integrating backbone in my project. The very first difficulty that i had was response from backend was not JSON Array or not designed for backbone. Here is an example.
//A backbone model
var Person = Backbone.Model.extend({});
// A backbone collection
var PersonCollection = Backbone.Collection.extend({
model : Person,
url: '/people'
});
So consider this, that when I request /people it does not return JSON array of people. Instead it return something like:
{header: "some str", people: ["person", "array", ".."], stats: "something is here" }
The problem with it is backbone is unable to assign this JSON response to models. Is there any tweak that can be done in controller on response. So accessing model can be normal.
Any before/after hook.
FYI: backbone is getting response from server, I can see it under "responseText" key.
Any help is highly appreciated.

Backbone supports this. I ran into the same issue when consuming data from Parse.com. In your case, when you have a /people endpoint that does not return an array, you can override the Collection.parse function to show Backbone how to find the array it is looking for:
var PersonCollection = Backbone.Collection.extend({
model : Person,
url: '/people',
parse: function(resp, xhr) {
this.header = resp.header;
this.stats = resp.stats;
return resp.people;
}
});
If you need to do more in this function, then you should. In a similar way, you can override Model.sync if you need to.

Related

Get same Item collection but with different limits

In my Backbone project, I am getting a collection of Items through the following Model:
MyApp.models.Items = Backbone.Model.extend({
url: "getItems"
});
and then later:
var model = new MyApp.models.Items();
model.fetch().then(function(data){
// do something here with fetched data
});
This Implementation works fine but I have a situation where I am getting all the Items on Home page and only 3 items in other page.
I feel it will be overkill if I fetch all the Items and then using the above model to limit it to 3 Items.
How can I use the same model to get a limited number of items or all items?
PS: I am new to Backbone.
The Backbone collection (Doc : http://backbonejs.org/#Collection) is a set of models.
Its best to use a backbone collection when you are dealing with data that is used to populate UI components like data gird / table, data lists e.t.c were you need a set of data.
MyApp.collections.ItemCollection = Backbone.Collection.extend({
model: Item,
url: "getItems"
});
The model attribute inside the collection specifies the type of data the is present in the collection. The collection uses this information to efficiently manage data inside it (merge during server fetch for already existing models /can pass raw json data to methods like add).
Using the collection fetch method(http://backbonejs.org/#Collection-fetch), data is fetched from the server.
var itemCollection = new MyApp.collections.ItemCollection();
itemCollection.fetch({
// The data property is used to send input data to the server method.
// Any data that will be required by the server method can be passed using this.
data: {
limit : 5
},
success : function(collection, response, options) {
//Do your logic
console.log("Success...");
}
error: function(collection, response, options) {
//Do your logic
}
});
In your scenario, you say you fetch all the items in homepage and only use part of it in other page.
For me, I would use router.
When the user moves from homepage to other page, you don't need to fetch new items, just choose the needed items (3 items) and render it.

Backbone.js adding model retrieved from server to a collection

I would like to know if it possible to add a model to a collection in the following manner.
I tried it and it doesn't work. If I add the JSON [] directly it does. I know this is a little strange but I am trying to get a better understanding of how BB works. Thanks.
var UserModel = Backbone.Model.extend({
urlRoot: '/users',
});
var UserModels = Backbone.Collection.extend({
url: '/users',
model: UserModel
});
var user = new UserModel({id:1});
user.fetch({ // get the model
success: function (user) {
var users = new UserModels();
users.add(user); // add the model to a collection
}
});
The following model is being echoed from the server:
[{"name":"john","email":"john#bb.com"}]
Since the response from the server is an array with a single element, you will need to add a parse function that returns the first element of the array:
var UserModel = Backbone.Model.extend({
urlRoot: '/users',
parse: function(response){
if(response && response.length) return response[0];
}
});
That should allow the model to correctly parse the attributes in this response from the server: [{"name":"john","email":"john#bb.com"}].
By the way, you are creating the users collection in the success function, so it won´t be available outside that function. It might just be the sample code you posted, but you could create the users collection outside and just add the model in the success function:
var users = new UserModels();
var user = new UserModel({id:1});
user.fetch({ // get the model
success: function (user) {
users.add(user); // add the model to a collection
}
});
I have created a fiddle so you can give it a try. (I have used fiddle echo service, so thats why I have changed the url and it is using a POST). If you run it and check the console, you will see the users collection being logged and you can check its models property.

Multiple Backbone.js collection options?

Intro:
Building in node.js and express on the backend, I am sending a res.json(details) to the localhost:3000/me route containing the users session information.
So that on the client side I can work with that specific user, for example on the client side initialization I write some code like this.
var me = new MeModel();
me.fetch({
success: function(response) {
App.data.me = me;
var messages = new MessagesCollection([], { id: response.get('user_id') });
messages.fetch({
success: function() {
App.data.messages = messages;
App.core.vent.trigger('app:start');
}
});
}
});
You see I fetch the me model and use that to filter the messages in the MessagesCollection.
Question:
In my MessagesCollection I pass options like this.
module.exports = MessagesCollection = Backbone.Collection.extend({
initialize: function(models, options) {
this.id = options.id;
},
url: function() {
return '/api/messages/' + this.id;
},
model: MessageModel,
//url: '/api/messages'
});
This is great for getting the desired models when using var messages = new MessagesCollection([], { id: response.get('user_id') });
My question is when somewhere else I run window.App.data.messages.create(Message); this wants to POST to /api/messages/:id when I want to POST to the regular collection?
Theory:
So obviously I would say the best thing is to rethink how I filter the models in the fetch method.
So basically to simplify this question I need to filter the collection upon .fetch() GET... and set no filters upon .create() POST
BTW I am using marionette, maybe that can help with something?
model.url() Returns the relative URL where the model's resource
would be located on the server. If your models are located somewhere
else, override this method with the correct logic. Generates URLs of
the form: "[collection.url]/[id]" by default, but you may override by
specifying an explicit urlRoot if the model's collection shouldn't be
taken into account.
Delegates to Collection#url to generate the URL, so make sure that you
have it defined, or a urlRoot property, if all models of this class
share a common root URL. A model with an id of 101, stored in a
Backbone.Collection with a url of "/documents/7/notes", would have
this URL: "/documents/7/notes/101"
http://backbonejs.org/#Model-url
So you can define method url at MeModel and generate url there ( if there are no other users - you can just return string "/me" or generate in based on model properties ( for example switch if model has id )

save in server by model or by collection?

I'm confused about send collection or model to the server.
This is my model:
var Person = Backbone.Model.extend({
defaults : {},
initialize : function() {}
});
and this is my collection:
var Usercollection = Backbone.Collection.extend({
model : Person,
url : 'https://api.parse.com/1/classes/_User/'
});
Now, if I would save a model on the server I have first to add in a collection and use save on model or first add in a collection and use save on collection? And least, I have to write an ajax call to post the collection or model in a server?
You should save your model to server.
Save a model: Call save() on model e.g.
var user = new UserModel();
user.save({name: 'SJ', age:'35'}, {
success: function (user) {
// I get a model here with id
}
});
Read these links for more information.
How to save your model data: SO Link
Sample code - by Thomas Davis in his screencast # backbonetutorials.com - Must watch
Server side code for wine cellar app
I have given you the link of server side code to have a look at the APIs to make things more meaningful to you. Hope this helps!
If you want to add the model to the collection after the model is saved, you need to use .create on the collection , which fires the add event on the collection after it gets created..
this.collection.create(model.toJSON() , options);
Use collection.create();
http://backbonejs.org/#Collection-create
Convenience to create a new instance of a model within a collection.
Equivalent to instantiating a model with a hash of attributes, saving
the model to the server, and adding the model to the set after being
successfully created. Returns the new model. ...
var Library = Backbone.Collection.extend({
model: Book
});
var nypl = new Library;
var othello = nypl.create({
title: "Othello",
author: "William Shakespeare"
});

Node.js server emit data to backbone model

I'm trying to integrate socket.io with backbone.js, so basicly I have a node server that gets data from a database and emit the data to a backbone client, the client's model should somehow retrieve the incoming data but I'm not sure how to put socket.io in the model now, just getting confused after lost of tries. Any expert please enlight me would be much appreciated!
Node server emit data to client in url /pics
app.get('/pics', function(req, res){
db.collection('pics', function(err, collection) {
collection.find().toArray(function(err, items) {
io.sockets.on('connection', function (socket) {
socket.emit('news', items);
});
});
});
});
Client in Backbone model should retrieve the emitted data(this model works for normal http data sending):
window.Pic = Backbone.Model.extend({
urlRoot: "/pics",
idAttribute: "_id",
initialize: function (){},
defaults: {
_id: null,
name: "",
date: "",
}
});
window.PicCollection = Backbone.Collection.extend({
model: Pic,
url: "/pics"
});
I must admit using Backbone on node + socket.io is quite interesting. Still haven't put my mind into it though. First thing first, have you considered using a plugin Backbone for websockets? Some people have created such.
To give another approach, I think you don't really have much of a choice. Using socket.io to listen to incoming data would result in something like that:
socket.on('model', function(attributes) {
// do something
});
So you'd have to have access to some collection where you could update manually your model.
If you wish to really use socket.io INSIDE your model, a more transparent way would be to extend your model to start listening to some custom event on its creation. I'll link a jsfiddle to show what could be done.
Edit: here you go.
Note that this is full of boilerplate. I'm trying to figure out a way to do a generic socketModel. I'll update if I find one.

Categories