BackboneJS Update Model and REST API - javascript

I am using BackboneJS and have a model object to update.
self.model.save(
{
urlRoot: +self.model.get("personId")+"/deactivate"
},
{
success: function (model){
self.showMessage('Person deactivated', true, true);
self.model.fetch();
},
error : function(){
$("#save", self.el).button("reset");
}
});
Now my REST method looks like
#PUT
#Path("{id}/deactivate")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public CompanyVO deactivatePerson(#PathParam("id") Long id, PersonVO personVO) {
return modifyPerson(id, personVO);
}
My question is there is some issue how I am setting urlRoot to call the corresponding REST method.
Please let me know the correct way so that I can call the REST method and update the Person object.

The save method prototype is : model.save([attributes], [options])
The first parameter is attributes. Second one is options, such as url, success, error methods can be specified.
If you already have set all attributes of a model, then pass '[]' as first parameter to save i.e.
self.model.save([],{
urlRoot: +self.model.get("personId")+"/deactivate, //ensure protocol + domain name are added
success: function (model){
self.showMessage('Person deactivated', true, true);
self.model.fetch();
},
error : function(){
$("#save", self.el).button("reset");
}
});

Related

Backbone js: Not getting data from model while fetching data using rest api in collection

//Declare model
app.models.Items =Backbone.Model.extend({
defaults: {
id: '',
name : ''
}
});
//fetch data using collection
app.models.ItemsCollection = Backbone.Collection.extend({
model: app.models.Items,
url: urlprefix + id + "/items",
});
//Create Instance of Collection
app.models.ItemsModel = new app.models.ItemsCollection();
app.models.ItemsModel.fetch({
async: false,
// in success get response and add response in model
success: function(response) {
for (i = 0 ;i < response.models[0].attributes.elements.length;i++){
app.models.ItemsModel.add(new app.models.Items(response.models[0].attributes.elements[i]));
}
},
error: function (errorResponse) {
console.log(errorResponse);
}
});
In controller i have to set new property in my model but i dont have
get model. in console i tried item.models[0] to fetch a first model but it show
me undefined.
var item = new app.models.Items();
item.set("Id", 'TG');
item.set("name", 'Gokul');
item.save(null, {
success: function(model, response){
console.log("save");
},
error: function(error, response){
console.log("Error: while saving Account data:" +JSON.stringify(error));
}
});
I am new in backbone.js so, please help me. if i did anything wrong in my code
There are several issues here:
There is no async: false option when calling fetch on a collection. When you call fetch(), an asynchronous call is made to the server to get the results. You wouldn't want your browser to hang while that happens.
You don't need to set the individual models in the collection. Backbone does that for you, assuming your REST endpoint is returning valid JSON.
I would get rid of the for loop in your success method. You don't need to do that.
If necessary, you can override the parse option in your Model definition to handle custom processing of the response for each Model.
You also want to set the urlRoot on your Model definition so you can use the model outside of the collection as you did.
Finally, it looks like you have the url property on your collection set incorrectly. You don't want the id in there.
All told, your code should look something like the following:
app.models.Items =Backbone.Model.extend({
urlRoot: urlprefix + '/items',
defaults: {
id: '',
name : ''
},
parse: function(response, options) {
//your custom code here if necessary
}
});
app.models.ItemsCollection = Backbone.Collection.extend({
model: app.models.Items,
url: urlprefix + "/items",
});
That's it. Then you can create a collection and fetch the current items:
var items = new app.models.ItemsCollection();
items.fetch();
But remember, that fetch() is an asynchronous method. You have to wait for the results to come back from the server before you can expect any items in the collection. That's what the success option is for.
And, you can now create an item independently, as you did, and now that the urlRoot is set on the model, it should save to your server correctly.
// Not sure you want to be setting the ID here in case you want it to
// be set on the server when it is persisted
var item = new app.models.Item({
"name": "Gokul"
});
item.save();
You can then manually add the item to your collection:
items.add(item);
Or you can just fetch the items again and it should be there now:
items.fetch();
Just remember again, the fetch() will only work if you have waited for the item to be saved to the server (asynchronously) first.
Good luck!

Using Model.destroy

After going through the backbone documentation, it is evident that to send a delete request for a model we need to set the urlRoot and id. Another technique which came to my mind was to implement a sync for my model.
since my server uses POST for delete, i use emulateHTTP = true.
How can i acheive the above task so that the request url for my model will be of the form
http://myWerService.com/myresource/deleteMyModel?modelName="abc"
So, how can i set my id as modelName
What is the difference between the below two url patterns
http://myWerService.com/myresource/deleteMyModel?modelName="abc"
http://myWerService.com/myresource/deleteMyModel/abc
The reason being, i saw every example use the second url pattern and i have no idea about the distinction between the two.
I have the url set for this model for create request, how can i use a different url (i want to use the above specified url) for sending a delete request
I am not sure if this is exactly what you are asking, but maybe this example will help:
var MyModel = Backbone.Model.extend({
ID: 0,
Name: '',
... other attributes for the model ...
},
initialize: function (id) {
this.ID = id;
},
idAttribute: 'Name', // set the id attribute as the name attribute
// you can have different urls for different operations
methodToURL: {
'read': 'GetModel',
'update': 'UpdateModel',
'delete': 'DeleteModel'
},
// overwrite the sync function
sync: function (method, model, options) {
options = options || {};
options.url = model.methodToURL[method.toLowerCase()];
switch (method) {
case 'read':
case 'update':
case 'delete':
options.url += '/' + this.id;
break;
}
Backbone.sync(method, model, options);
}
});

How do I modify the URL generated during Backbone sync, but only for a specific requests

I would like to change the URL generated when my entity calls destroy. Instead of writing an HTTP DELETE to /{Action}/{EntityID}, I would like to send /{Action}/{EntityID}/{SecondEntityID}.
item.destroy({
data: $.param({
playlistId: playlistId
}),
processData: true,
success: callback,
error: function (error) {
console.error(error);
}
});
I thought that something like this might work, but it doesn't seem to append on any additional parameters. Do I have to implement my own sync method in its entirety if I want to extend just destroys' URL?
You can override is through passing in a .url property in options when you call destroy. Since I assume you'd want to do this for every single call, you can do this:
var MyModel = Backbone.Model.extend({
destroy: function(options) {
// Override URL
options || (options = {});
// You can put whatever you need here,
options.url = 'http://www.awesome.com/destroy/' + this.get('id') + '/' + this.get('secondaryId');
// Call Model.destroy().
// We are reusing the existing functionality from Backbone.Model.destroy().
Backbone.Model.prototype.destroy.apply(this, arguments);
}
});
var m= new MyModel({ id: 123, secondaryId: 456 });
// Note: You need to set 'id' in order for destroy() call to be successful.
m.destroy({
sucess: function() { console.log('good'); },
error: function() { console.log('bad'); }
});
If you open up Firebug or Chrome Dev Tools, you should see an XHR/AJAX call was made to www.awesome.com.
Since you mentioned that you want to do this across ALL entities that you have, what you can do in that case is to create a BaseModel in your application, and have all your entities extend from it.
Anyway, hope this helps!
JSFiddle for this: http://jsfiddle.net/EwQaD/

How to wait to render view in backbone.js until fetch is complete?

I'm trying to understand how a portion of backbone.js works. I have to fetch a collection of models once the app begins. I need to wait until fetch is complete to render each view.
I'm not 100% sure the best approach to take in this instance.
var AppRouter = Backbone.Router.extend({
routes: {
"": "home",
"customer/:id": "customer"
},
home: function () {
console.log("Home");
},
customer: function (id) {
if (this.custromers == null)
this.init();
var customer = this.customers.at(2); //This is undefined until fetch is complete. Log always says undefined.
console.log(customer);
},
init: function () {
console.log("init");
this.customers = new CustomerCollection();
this.customers.fetch({
success: function () {
console.log("success");
// I need to be able to render view on success.
}
});
console.log(this.customers);
}
});
The method I use is the jQuery complete callback like this:
var self = this;
this.model.fetch().done(function(){
self.render();
});
This was recommended in a Backbone bug report. Although the bug report recommends using complete, that callback method has since been deprecated in favor of done.
You can also do this with jquery 1.5+
$.when(something1.fetch(), something2.fetch()...all your fetches).then(function() {
initialize your views here
});
You can send your own options.success to the collections fetch method which runs only when the fetch is complete
EDIT (super late!)
From the backbone source (starting line 624 in 0.9.1)
fetch: function(options) {
options = options ? _.clone(options) : {};
if (options.parse === undefined) options.parse = true;
var collection = this;
var success = options.success;
options.success = function(resp, status, xhr) {
collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
if (success) success(collection, resp);
};
Note the second to last line. If you've passed in a function in the options object as the success key it will call it after the collection has been parsed into models and added to the collection.
So, if you do:
this.collection.fetch({success: this.do_something});
(assuming the initialize method is binding this.do_something to this...), it will call that method AFTER the whole shebang, allowing you trigger actions to occur immediately following fetch/parse/attach
Another useful way might be to bootstrap in the data directly on page load. This if from the
FAQ:
Loading Bootstrapped Models
When your app first loads, it's common to have a set of initial models that you know you're going to need, in order to render the page. Instead of firing an extra AJAX request to fetch them, a nicer pattern is to have their data already bootstrapped into the page. You can then use reset to populate your collections with the initial data. At DocumentCloud, in the ERB template for the workspace, we do something along these lines:
<script>
var Accounts = new Backbone.Collection;
Accounts.reset(<%= #accounts.to_json %>);
var Projects = new Backbone.Collection;
Projects.reset(<%= #projects.to_json(:collaborators => true) %>);
</script>
Another option is to add the following inside of your collections initialize method:
this.listenTo(this.collection, 'change add remove update', this.render);
This will fire off the render method whenever the fetch is complete and/or the collection is updated programmatically.
You Can Use on and Off Methods
if you want to add trigger method like suppose if you want on success you want to call render method so please follow below example.
_this.companyList.on("reset", _this.render, _this);
_this.companyList.fetchCompanyList({firstIndex: 1, maxResult: 10}, _this.options);
in Model js please use like
fetchCompanyList: function(data, options) {
UIUtils.showWait();
var collection = this;
var condition = "firstIndex=" + data.firstIndex + "&maxResult=" + data.maxResult;
if (notBlank(options)) {
if (notBlank(options.status)) {
condition += "&status=" + options.status;
}
}
$.ajax({
url: "webservices/company/list?" + condition,
type: 'GET',
dataType: 'json',
success: function(objModel, response) {
UIUtils.hideWait();
collection.reset(objModel);
if (notBlank(options) && notBlank(options.triggerEvent)) {
_this.trigger(options.triggerEvent, _this);
}
}
});
}

Backbone.js is not posting to the server on a model change? Why?

I have the following:
// MODEL
NotificationModel = C.BB.Model.extend({
defaults : {
read : false
},
urlRoot : '/notifications'
});
// COLLECTION
NotificationCollection = C.BB.Collection.extend({
model: NotificationModel,
url: '/notifications',
initialize : function() {
var me = this;
me.fetch();
}
});
Later in the view I have:
....
onCollectionAdd : function(m,c,cfg) {
m.set({read: true},{silent: false});
The set is changing the items value but Backbone is not posting the update to the server. Any suggestions? Thanks
You need to call m.save(), which will call correspondent method create() or update().
Method set() trigger only change() event, which not save any data in backend
You could bind an event to the collection to save them:
NotificationCollection = C.BB.Collection.extend({
model: NotificationModel,
url: '/notifications',
initialize : function() {
this.fetch();
this.bind('change', this.save, this);
}
});
Note there is also the Collection.create method wich add a new model to the collection and save the collection on the server.

Categories