backbone.js collection sync with server - javascript

I'm trying to figure out how to make a backbone.js Collection stay synchronized with a server at the end of an url.
I would like to be able to add a model to a collection and have the collection automatically do a POST with the new model to the collection url...
I cant seam to find the functionality for this anywhere.

Models are never saved to the collection endpoint, they have their own url property to configure where they are saved.
Instead of calling add on the collection then save on the model, you can just call create on the collection and it'll do both, but you must configure the model's URL.
var MyModel = Backbone.Model.extend({
urlRoot: '/some/path'
});
var MyCollection = Backbone.Collection.extend({
url: '/some/path',
model: MyModel
});
var instance = new MyCollection();
instance.fetch(); //fetches at /some/path
// ...
instance.create({ foo: 'bar' }); // adds to collection and saves the new model
Documentation for create
In order for this to work, you should set the model property of the
collection.

Related

Backbone merge on some attribute, save on id

For an application i need to fetch default values, after which i merge in user specific values. These models are matched by a key attribute.
The defaults have no id the user specifics do have an id.
If i set my idAttribute to key it neatly merges the user specific values into the default models. But when i want to save this model, it will create the PUT url with the key attribute, because of the idAttribute. I want to save to collection.url + id, just as basic Backbone functionality.
Why not override the url? If a user edits to default model, it needs to POST to my REST server, normally a backbone model without an id will do this automatically. By overriding the URL, this doesn't work anymore.
changing the idAttribute before calling .save() doesn't seem to effect it.
Code example:
DefaultWeatherLimits = BackboneCollection.extend({
url: 'limits/default',
comparator: 'displayOrder',
model: WeatherLimit,
initialize: function () {
this.fetch();
}
});
Respond is an array like this (with more info in actual situation):
"[{"key":"MinHurricaneDistance","visualizationHint":"Value","value":300},{"key":"MaxHeadWavesHeight","visualizationHint":"Value","value":300}]"
The model looks like this:
WeatherLimit = Backbone.Model.extend({
idAttribute : 'key'
});
Now , as test add in a User Specific model:
var fake = this.add({id: 99, key: "MinHurricaneDistance", checked: true}, {merge: true});
I want this fake model to save to 'limit/default/99', but it will save to 'limit/default/MinHurricaneDistance'
And i want the MaxHeadWavesHeight model to POST to '/limit/default', it will get an id in return and after i can save it to that id.

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"
});

How to handle custom response in Backbone model

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.

Categories