Bulk delete using backbone - backbone.js

I have a view which contains list of employees, end user select the employees and delete the employees more than one at ones.
Each row of the list contains a check box. End user select multiple check boxes and press delete button. The selected records need to delete.
MVC controller takes care of the delete part. Signature of the delete method is:
DeleteEmployes(List<int> empIds).
How can I achieve this?
My backbone model is:
var emp = Backbone.Model.extend({
defaults:{
Id:null,
fname:null,
lname:nulll.
}
});

In order to delete all models with one request, you need to extend backbone's collection with a method that sends a HTTP DELETE request to a controller action that uses the 'DeleteEmployes(List empIds)' function. Something like this may do the trick.
Backbone.Collection.prototype.bulk_destroy = function() {
var modelId = function(model) { return model.id };
var ids = this.models.map(modelId);
// Send ajax request (jQuery, xhr, etc) with the ids attached
// Empty the collection after the request
// You may want to include this as a success callback to the ajax request
this.reset();
};

Create a Backbone Collection and loop through it, destroying each model. This will send the DELETE command for each model to the server.
var Employees = new Backbone.Collection([
{ name: 'Employee1' },
{ name: 'Employee2' },
{ name: 'Employee3' },
]);
Employees.each(function(model){
model.destroy();
});

Related

Backbone.js approach

I have a form (on localhost) with 2 fields:
First Name (text box)
Last Name (text box)
Once the form is submitted, I need to use API - https://beta.test.com/api
The documentation says -
"POST /user will add the details to system and generates a user ID which would be returned."
After I receive user ID in response, I need to call another endpoint -
"POST /user/metadata will fetch the metadata for a previously added user."
I have to build this in backbonejs. What should be my approach? Do you have any tutorials which I can look at?
I did some code but it gave me - "Access-Control-Allow-Origin". I have checked on server and the API already has cross domain allowed for all.
Please suggest.
For a good example look at TODO app in backbone way.
I will also suggest you to read Backbone's documentation and view the source code.
It will documented so you can find all you need there, if no look into the source.
Simple implementation of your form could be achieved like this:
For interaction with API and data exchange via REST create User model:
var UserModel = Backbone.Model.extend({
urlRoot: 'your/api/path',
default: { // this will be setted when model attributes are empty
firstname: 'Default Name',
lastname: 'Default Lastname'
}
});
Form view which will render you form and will bind model's attributes to the form's elements:
var UserForm = Backbone.View.extend({
initialize: function() {
this.render();
},
el: '.form-container', // this will attach view to the DOM's element with 'form-container' class
template: _.template($('#user-form').html()),
events: {
'submit': 'onFormSubmitted',
// validation logic could be added here
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
},
onFormSubmitted: function(e) {
e.preventDefault(); // we don't need to submit the form
// get form elements here and setting on model
// saving model at the end
var firstName = this.$('input[name="firstname"]').val();
var lastName = this.$('input[name="lastName"]').val();
this.model.set({firstname: firstName, lastname: lastName});
this.model.save(); // this will make POST request to your API
}
});
And then initialize you view and pass User model.
var userForm = new UserForm({model: new UserModel()});
I have left the declaration of template for you.
There is a lot of staff for cross origin requests policy issues when using Backbone. Actually it's not the Backbone thing. Backbone uses $.ajax to interact with REST-full resources. So you just need to configure $.ajax. Look here.

Why backbone add extra parameter to url path?

I am using backbone.marionette (1.0.0) and node.js (0.10.22). Wondering why backbone add extra parameter when I try to save model data with node.js REST call.
model.js
Backbone.Model.extend ({
urlRoot: function (){
return '/path/' + myApp.companyId;
},
defaults: {
companyId: '',
// other attributes
},
// doesn't use 'id' in model instead companyId
idAttribute: 'companyId'
});
Before view is loaded, I would request model data with myApp.request ('entities:myModel') which issued model.fetch () and node.js backend would fire GET /path/1 route. No issue.
However, when an update button is clicked on the view, this.model.save () would fired PUT /path/1/1. It should be PUT /path/1, with only a single '1' in url path.
view.js:
clicked: function () {
var formData = Backbone.syphon.serialize (this);
this.model.set (formData);
var promise = this.model.save ();
promise.done ().fail ()
}
How can I stop backbone.sync from appending extra parameter to url path? Thanks for taking time out to read this, and I appreciate your help.
You're setting urlRoot incorrectly on the model. It should be
Backbone.Model.extend ({
urlRoot: "path",
// etc
});
Backbone willa dd the ids on it's own.
If you want to specify the ids in your function, use the url function.

backbone-relational: usage with standalone model without relations

I am using backbone-relational. The usage for a onetomany model works fine.
But I am having troubles using backbone-relational for a single/standalone model:
window.BeerOnlineShopPosition = Backbone.RelationalModel.extend({
urlRoot:"../api/beeronlineshoppositions",
idAttribute: 'id',
relations: [
],
defaults:{
"id":null,
"position_amount":""
}
});
window.BeerOnlineShopPositionCollection = Backbone.Collection.extend({
model:BeerOnlineShopPosition,
url:"../api/beeronlineshoppositions"
});
in main i have:
beeronlineshopproductDetails:function (id) {
var beeronlineshopproduct = BeerOnlineShopProduct.findOrCreate(id);
beeronlineshopproduct.fetch();
var beeronlineshopproduct_view = new BeerOnlineShopProductView({el: $('#content'), model: beeronlineshopproduct});
},
So, when jump to an existing records (...beeronlineshop/beeronlineshopproducts/#4), nothing happens. But debugging shows, that the fetch is executed and the view gets loaded. but the view is not rendered somehow.
When I refresh (f5), the view gets rendered correctly.
As mentioned the whole thing works for one-to-many model, so my question is:
did i make some trivial syntax-error on the model part?... or is there any other obvious reason for the troubles i have?
It may be because of the asynchronous request created by findOrCreate. beeronlineshopproduct.fetch() is making a request to the server but the view is being rendered before the server returns with a response.
You have two options. You can pass in the rendering of the view as a callback upon fetch's success like so:
beeronlineshop.fetch({
success: function() {
var beeronlineshopproduct_view = new BeerOnlineShopProductView({el: $('#content'), model: beeronlineshopproduct})
});
Or you can pass an initializer in your BeerOnlineShopProductView that listens to the its model syncing with the server, and calls for the view to re-render itself, like so:
window.BeerOnlineShopProductView = Backbone.View.extend({
initialize: function() {
this.listenTo (this.model, "sync", this.render)
},
})

Is there an equivalent to parse to use before syncing with the server?

In my backbone model, I parse the response from the server:
var MyModel = Backbone.Model.extend({
urlRoot: "/users",
parse: function(response){
var data = {};
data.id = reponse.userDetails.id;
data.name = response.userDetails.firstname + " " + response.userDetails.lastname;
data.description = response.userDetails.description;
return data;
}
});
var myModel = new MyModel({id: 1});
myModel.fetch();
The views that use this model can manipulate it, for example, if the user were to click on the view to "select" it, it would update the model...
myModel.set({selected: true});
...and the view would re-render based on the model's change event and highlight the "selected" user.
When it comes time to save the model to the server, how do I only send the attributes the server wants? and ignore the attributes which were added through user interaction.
OR
Should the data model always reflect what the server returns? If so, is there a better way to store the user interactions (whether the view is "selected")? Should it be a separate model than the actual data model?
Thanks
The model doesn't need to mirror the data on the server if that doesn't make sense for your application.
For the model's attributes, if you don't need to render those attributes in a template, then you can just override model.toJSON() to only serialize the attributes you want sent to the server. Be careful though, in this case if you are rendering your template (or anything else) using this.model.toJSON() then it will also be affected. If that's a problem then you can override model.sync() instead and manipulate the data passed in before sending it to Backbone.sync. For example:
var myModel = Backbone.Model.extend({
sync: function (method, model, options) {
// remove the unwanted attributes. Something like...
options.attrs = _.pick(model.attributes, 'attribute1', 'attribute2', 'attribute3');
return Backbone.sync.call(this, method, model, options);
}
});
Overriding model.toJSON as suggested by mu_is_too_short worked nicely for me.
In the model
function() {
var json = Backbone.Model.prototype.toJSON.call(this);
json.ExtendedFieldData = JSON.stringify(json.ExtendedFieldData);
return json;
},
We use model.attributes for templates.

backbone.js - how can i fetch local or server data

I am very new to backbone.js, to try it out I made a function to append an element using my array. But I don't know how to fetch the same from server or my local path.
I tried with some tutorial but still I couldn't get any good result. Can any one correct my function to fetch the data from local folder or server?
code :
this is my local path: '..data/data.json'
(function($){
var student = [
{name:'student1'},
{name:'student2'},
{name:'student3'}
]
var model = Backbone.Model.extend({
defaults:{
name:'default name'
}
});
var collection = Backbone.Collection.extend({
model:model
});
var itemViews = Backbone.View.extend({
tagname:'li',
render:function(){
this.$el.html(this.model.get('name'));
return this;
}
})
var view = Backbone.View.extend({
el: $("#contacts"),
initialize:function(){
this.collection = new collection(student);
this.render();
},
render:function(){
var that = this;
_.each(this.collection.models, function(item){
that.renderName(item);
})
},
renderName:function(item){
var itemView = new itemViews({model:item});
this.$el.append(itemView.render().el);
}
});
Collections have the url property which links to the url where the models can be fetched (in a proper JSON format of course).
If you have a RESTful API you can tie them directly to a collection on your backend.
In your case you can modify the collection definition as follows
var collection = Backbone.Collection.extend({
model:model,
url: '..data/data.json' //OR WHATEVER THE URL IS
});
Then when instantiating your collection you have to call the fetch() method to fill in the collection.
myCollection = new collection();
myCollection.fetch();
For more information see this post
Backbone will call GET, POST, DELETE, etc on that same url depending on what needs to be sent or received from the server. So if you are building the REST api, your controller or router should route the appropriate functions to those methods. See below for exact mapping:
create → POST /collection
read → GET /collection[/id]
update → PUT /collection/id
delete → DELETE /collection/id
As a side note, if you have no control over the JOSN that is returned from the server, you can format it in any format you like in the parse function.
parse: function(response) { return response.itemYouWantAdded; }
This would be the case if your server is returning an object within an object, such as twitter feeds.
Or you could simply populate the model from the response manually in the parse function
parse: function(response) { var tmpModel = {
item1:response.item1,
item2:response.item2
};
return tmpModel; }
Hope this helps.
You can set a URL for your model or for your collection. Then when you run fetch it will read your JSON straight into either a single model or a collection of models. So in your case, your collection might look like
var collection = Backbone.Collection.extend({
url: '..data/data.json',
model: model
});
collection.fetch(); // Could also use collection.reset()
You just need to make sure your JSON is formatted properly to match your model's attributes.

Resources