Backbone merge on some attribute, save on id - javascript

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.

Related

Backbone - receiving DELETE data in the back end

Say you have a model with an id, and you want to delete it in the database. So you call the destroy() method on that model (as below in the code example). That sends an OPTIONS HTTP request, followed by a DELETE HTTP request. My issue is that while I'm catching the DELETE request nicely on the server side, I can't find any information telling me what the model id is - it's not a parameter in the request and it's not in the URL. How do I find this information? I can't see it in the documentation here. Here is a link to the repo where I'm storing the code.
removeElement: function() {
// DELETE in DB
this.model.destroy();
this.remove();
this.unbind();
},
What I would expect is that the HTTP request would have a param like { 'id': 42319 } or some such.
You probably need to set the model ID attribute. The id set automatically by Backbone on the client is cid and not id. Note that a common gotcha with DBs that use a different unique key (like MongoDB) is not mapping from that key to ID as described in the docs
For example:
var Model = Backbone.Model.extend({
idAttribute: "_id"
//other model setup code
});
My problem was that I was defining the url attribute in BOTH the model AND the collection. You should only define url in the collection. Stupid mistake.

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

backbone.js collection sync with server

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.

Search criteria form and collections

In my application, I would like to create a search form in order to retrieve some users. This form contains many criteria (lastname, firstname, birthdate, etc.). But I do not understand how I can post my form in order to filter my collection. I can not use fetch method because if I use GET method, my search criteria will be displayed in the URL. In fact I would like to submit a POST request (which contains the search criteria serialize in JSON) to the server and retrieve a user list.
I have read the backbone documentation but I do not found anything that allow me to do that. This functionality is not supported by backbone ? There is some workarround to implement this requirements ?
Thanks in advance
In short, I don't think backbone is a good fit for what you are describing. Read on for a longer version...
Based on your question, I think backbone would be well suited to display your collection of users, but not so good at the submission of your filter criteria.
You could create a criteria model and set the attributes of the model to Username, Birthday, etc and then you could post it to the server using backbone. However when you save it using backbone, it is assumed that you saved the criteria. Any result that comes back from the server from that POST is assumed to be updated properties of the criteria, and not a list of users.
Tim is correct that this isn't exactly what Backbone is meant for. That being said I think I would still at least use a Backbone model to track the state of the search criteria. On this model I would add a custom method for activating search that would serialize the model's state and POST it to the server itself. On the success of this method, I would use the results to reset the current user collection.
Here is my idea in code:
var SearchModel = Backbone.Model.extend({
defaults: {
firstName: "*",
lastName: "Smith"
},
search: function() {
$.ajax({
dataType: "json",
type: "POST",
data: this.toJSON(),
success: function(data) {
this.options.peopleCollection.reset(data);
}
})
}
});
var myPeopleCollection = new PeopleCollection();
var mySearch = new SearchModel({ peopleCollection: myPeopleCollection });
mySearch.set({ firstName: "Steve"});
mySearch.set({ lastName: "Smith" });
mySearch.search();

Categories