Backbone parsing this.model.destroy - javascript

INTRO
I Am having having issues trying to parse my models before I send them to my web service.
I have a REST web services set-up which is working fine, I have my backbone set-up to parse the web services JSON reponse, which also works fine. I am able to display the JSON objects
The problem is when I try to delete or update the model, backbone never parses the model before it sends it back to the server and the server always receives null.
Here is my code:
Teacher Model
window.Teacher = Backbone.Model.extend({
urlRoot: "http://localhost:8080/SIMS/resource/teacher",
defaults: {
"id": null,
"Name": "",
"Password": "",
"email": "",
"dob": "",
"type": ""
},
parse: function(response){
console.log("................................. response test.........");
response.id = response.idTeacher;
console.log("..........."+response.name);
console.log("..........."+response.idTeacher);
response.Password = response.password;
response.Name = response.name;
delete response.name;
delete response.password;
delete response.idTeacher;
return response;
} ,
toJSON: function(){
var attrs = _.clone(this.attributes);
attrs.name = attrs.Name;
delete attrs.Name;
attrs.password = attrs.Password;
delete attrs.Password;
attrs.idTeacher = attrs.id;
delete attrs.id;
return attrs;
}
});
window.TeacherCollection = Backbone.Collection.extend({
model: Teacher,
url: "http://localhost:8080/SIMS/resource/teacher",
parse: function(response){
for (var i=0; i<response.length; i++)
{
console.log("...........help");
response[i].id = response[i].idTeacher;
response[i].Password = response[i].password;
response[i].Name = response[i].name;
console.log(".........."+response[i].Name);
delete response[i].name;
delete response[i].password;
delete response[i].idTeacher;
}
return response ;
}
});
Teacher View: save function
saveTeacher: function() {
this.model.set({
Name: $('#Name').val(),
email: $('#email').val(),
Password: $('#Password').val(),
dob: $('#dob').val(),
type: $('#type').val()
});
if (this.model.isNew()) {
var self = this;
app.teacherList.create(this.model, {
success: function() {
app.navigate('admin/teacher/'+self.model.id, false);
}
});
} else {
this.model.save();
}
return false;
},
Web Service
#PUT #Path("{id}")
#Consumes({"application/xml", "application/json"})
#Produces({"application/xml", "application/json"})
public void update(Teacher T){
System.out.println("Updating Teacher:" + T.getName());
teacherejb.edit(T);
}
Question
Since I have the parse function I now use .attributes instead of toJSON() and this works fine.
Example:
render: function(eventName) {
$(this.el).html(this.template(this.model.attributes));
return this;
},
But when trying to call this.model.save in the saveteahcer function it never parses before I send it to the server, Im not sure how to parse it first and then send it to the server. When I debug the code the web service always receives null, how do I get my web service to properly receive the teacher object ?

The parse method is called after the server response, see Backbone documentation:
parsemodel.parse(response, options)
parse is called whenever a model's data is returned by the server, in fetch, and save.
I would suggest that you use validate to modify/update the data before send it to server:
validatemodel.validate(attributes, options)
This method is left undefined, and you're encouraged to override it with your custom validation logic, if you have any that can be performed in JavaScript. By default validate is called before save [...]

Related

Send PUT request with Backbone

I have to make service call with backbone to update user settings. here is the simplified code:
var settingService = Backbone.Model.extend({
"url": "usersettings"
});
var SettingsView = Backbone.View.extend({
initialize: function() {
this.services = {
"userSettingsService": new settingService()
};
},
saveSettings: function() {
this.services.userSettingsService.save({
"currency": "USD",
"dateFomat": "DD-MM-YYYY"
})
}
});
var settings_view = new SettingsView();
settings_view.saveSettings();
http://jsfiddle.net/ovg3kyqz/2/
when I call saveSettings the POST request is made which is not supported by backend. I need to make PUT request. I know that Backbone decides whether model is new based on its id and if so will send a PUT request
I can set
this.services.userSettingsService.set("id", 1)
and then on saveSettings a PUT request will be made but the request body will have {id: 1,...} which is not really what I want.
so how can I make a PUT request and not include id in the request body?
You could simply override the isNew method on your model to always return false and thus always send a PUT request. Something like
var settingService = Backbone.Model.extend({
url: "usersettings",
isNew: function () {
return false;
}
});
And a demo http://jsfiddle.net/ehhwqm70/
An alternative to overriding isNew (that I find more explicit) would be to override model.sync:
var settingService = Backbone.Model.extend({
url: "usersettings",
sync: function(method) {
if (method === "create") {
arguments[0] = "update";
}
return Backbone.sync.apply(this, arguments);
}
});
Demo: http://jsfiddle.net/pytpfnar/1/

What is the proper way to update hierarchical model on changing?

I have the following dialog model:
var DialogModel = Backbone.Model.extend({
user: null,
constructor: function () {
// Initialize user model
this.user = new BW.user.UserModel();
Backbone.Model.apply(this, arguments);
},
parse: function (attributes) {
_.isObject(attributes) || (attributes = {});
// update user's model data
this.user.set(attributes.user);
delete attributes.user;
return attributes;
},
toJSON: fucntion () {
var json = Backbone.Model.prototype.toJSON.call(this);
// serialize user's model data to JSON
_.extend(json, user: this.model.toJSON());
}
});
As you can see from the code above, I store user model into DialogModel and set data on parse and serialize in toJSON.
As some point in time I get dialog:update socket message with the following data:
{
id: 1,
message: 'message',
user: {
<JSON USER DATA>
}
}
To update dialog based on this message data I do the following:
eventBus.on('dialog:update', function (json) {
dialogModel.set(json);
});
But the problem is that user model don't get updated becase parse method does't execute.
So my question is how could I update user model on set method?
One option is to override model.set. Adding something like the following to your DialogModel will do the trick:
set: function (attributes, options) {
this.parse(attributes);
Backbone.Model.prototype.set.apply(this, arguments);
},
Note that I've chosen to call the parse method, since it nicely sets the user data and deletes it from the attributes for us (thus preventing that data from being set on dialogModel).
Click here for a fiddle demonstrating this solution.

Models are not serialized with Ember.js and WebApiAdapter

I'm trying to use the Ember.js MVC4 Spa Template with my own Models, but I'm not getting this to work.
For now, the serverside code is is working. The result to the browser is correct. But Ember-Data, or the custom WebApi - Serializer, is not able to prepare the Data.
I have two Models:
Patient:
App.Patient = DS.Model.extend();
App.Patient.reopen({
patientId: DS.attr('number'),
firstName: DS.attr('string'),
lastName: DS.attr('string'),
aufenthalte: DS.hasMany('aufenthalt'), //, { async: true }
fullName: function () {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName'),
});
App.PatientSerializer = DS.WebAPISerializer.extend({
primaryKey: 'patientId',
// ember-data-1.0.0-beta2 does not handle embedded data like they once did in 0.13, so we've to update individually if present
// once embedded is implemented in future release, we'll move this back to WebAPISerializer.
// see https://github.com/emberjs/data/blob/master/TRANSITION.md for details
extractArray: function (store, primaryType, payload) {
var primaryTypeName = primaryType.typeKey;
var typeName = primaryTypeName,
type = store.modelFor(typeName);
var data = {};
data[typeName] = payload;
data.aufenthalte = [];
var normalizedArray = payload.map(function (hash) {
hash.aufenthalte.map(function (aufenthalt) {
data.aufenthalte.push(aufenthalt);
});
hash.aufenthalte = hash.aufenthalte.mapProperty('aufenthaltId');
return hash;
}, this);
payload = data;
return this._super.apply(this, arguments);
},
normalizeHash: {
patient: function (hash) {
hash.patientId = hash.id;
return hash;
}
}
});
Aufenthalt:
App.Aufenthalt = DS.Model.extend({
aufenthaltId: DS.attr('number'),
name: DS.attr('string'),
patientId: DS.attr('number'),
patient: DS.belongsTo('patient'),
});
App.AufenthaltSerializer = DS.WebAPISerializer.extend({
primaryKey: 'aufenthaltId',
normalizeHash: {
aufenthalte: function (hash) {
hash.aufenthaltId = hash.id;
return hash;
},
}
});
When I get a List of "Patients" from my Controller, the Datamodels are filled correctly (I can check it in the Chrome Ember plugin.) When I hit a Action with the Patient Id, I get the error: "Error while loading route: TypeError: Cannot set property 'store' of undefined"
Thank You!
Did you added the proper router in app/routes folder, controller in app/controllers folder, and corresponding views and templates? Feel free to psot a link to your sample solution so I can download and have a look.
=== Update 2/22/2014 ===
I fixed the code. You should be able to download the modified solution from https://www.dropbox.com/s/4j3vbczqr4nx68m/EmberVSTemplateModified.zip. You should do a windiff on the two directories to see the changes. I need to change a few places to make it work for your scenario, including:
patient.js, make it directly extend from RESTSerialzer, and add extractSingle implementation.
change template of patsucheautocomplete.hbs
added patient\index.hbs . You should be able to remove patient.hbs file
paitentview.js (may not be necessary as it's all default)
modified controllers\htmlhelperextensions.cs, to make it work correctly for sub folder templates in debug mode.

What is the best way to add server variables (PHP) in to the Backbone.model using require.js?

I'm not sure what is the elegant way to pass server variables in to my Model.
For example, i have an id of user that has to be implemented on my Model. But seems like Backbone with require are not able to do that.
My two options are:
Get a json file with Ajax.
Add the variable on my index.php as a global.
Someone know if exists a other way. Native on the clases?
Trying to make work the example of backbonetutorials. I am not able to throw a callback when the method fetch().
$(document).ready(function() {
var Timer = Backbone.Model.extend({
urlRoot : 'timeserver/',
defaults: {
name: '',
email: ''
}
});
var timer = new Timer({id:1});
timer.fetch({
success: function(data) {
alert('success')
},
fail: function(model, response) {
alert('fail');
},
sync: function(data) {
alert('sync')
}
});
});
The ajax request it has been threw. But does not work at all. Because any alert its dispatched.
var UserModel = Backbone.Model.extend({
urlRoot: '/user',
defaults: {
name: '',
email: ''
}
});
// Here we have set the `id` of the model
var user = new Usermodel({id: 1});
// The fetch below will perform GET /user/1
// The server should return the id, name and email from the database
user.fetch({
success: function (user) {
console.log(user);
}
})
The server will reply with a json object then you can leave the rendering part for your backbone. Based on a template for the user.
You may also want to check these out: http://backbonetutorials.com/

javascript code architecture question

I'm about to make a web app which will have a pretty heavy client end. I'm not sure about the way to organize my javascript code, but here is a basic idea :
// the namespace for the application
var app = {};
// ajax middle layer
app.products = {
add : function(){
// send ajax request
// if response is successful
// do some ui manipulation
app.ui.products.add( json.data );
},
remove : function(){},
...
};
app.categories = {
add : function(){},
....
};
// the ui interface which will be called based on ajax responses
app.ui = {};
app.ui.products = {
add : function( product_obj ){
$('#products').append( "<div id='"+product_obj.id+"'>"+product_obj.title+"</div>" );
}
};
app.ui.categories = {};
Anybody got similar experiences to tell me the pros and cons of this approach? What's your way of designing client side javascript code architecture? Thanks.
[update] : This web app, as you see from the above, deals with products CRUD, categories CRUD only in a ajax fashion. I'm only showing an snippet here, so you guys know what I'm trying to achieve and what my question is. Again, I'm asking for inputs for my approach to organize the code of this app.
That is similar to the way I do my JavaScript projects. Here are some tricks I have used:
Create one file for each singleton object. In your code, store ajax, middle layer and ui interface in separate files
Create a global singleton object for the 3 layers usually in the project; GUI, Backend and App
Never use pure ajax from anywhere outside the Backend object. Store the URL to the serverside page in the Backend object and create one function that uses that URL to contact the server.
Have a JSON class on the server that can report errors and exceptions to the client. In the Backend object, check if the returned JSON object contains an error, and call the serverError function in the GUI class to present the error to the user (or developer).
Here is an example of a Backend object:
var Backend = {};
Backend.url = "/ajax/myApp.php";
Backend.postJSON = function(data, callback){
var json = JSON.stringify(data);
$.ajax({
type: "POST",
url: Backend.url,
data: "json="+json,
dataType: "json",
success: function(response){
if(response){
if(response.task){
return callback(response);
}else if(response.error){
return Backend.error(response);
}
}
return Backend.error(response);
},
error: function(response){
Backend.error({error:"network error", message:response.responseText});
},
});
};
Backend.error = function(error){
if(error.message){
Client.showError(error.message, error.file, error.line, error.trace);
}
};
This can be improved by storing the ajax object somewher in the Backend object, but it's not necessary.
When you build something non trivial, encapsulation is important to make things maintainable in long run. For example, JS UI is not just simple JS methods. A UI components consists of css, template, logic, localization, assets(images, etc).
It is same for a product module, it may need its own settings, event bus, routing. It is important to do some basic architectural code in integrating your chosen set of libraries. This had been a challenge for me when I started large scale JS development. I compiled some best practices in to a reference architecture at http://boilerplatejs.org for someone to use the experience I gained.
For client-side ajax handling I have a URL object that contains all my urls and than I have an ajax object that handles the ajax. This is not a centric approach.In my case I have I have different urls handling different tasks. I also pass a callback function to be executed into the ajax object as well.
var controller_wrapper = {
controller: {
domain: "MYDOMAIN.com",
assets: "/assets",
prefix: "",
api: {
domainer: "http://domai.nr/api/json/info",
tk_check: "https://api.domainshare.tk/availability_check"
},
"perpage": "/listings/ajax",
"save_image": "/members/saveImage",
"update": "/members/update",
"check_domain": "/registrar/domaincheck",
"add_domain": "/registrar/domainadd",
"delete_listing": "/members/deactivateProfile",
"save_listing": "/members/saveProfile",
"get_images": "/images/get",
"delete_image": "/images/delete",
"load_listing": "/members/getProfile",
"load_listings": "/members/getListings",
"loggedin": "/members/loggedin",
"login": "/members/login",
"add_listing": "/members/add",
"remove": "/members/remove",
"get": "/members/get",
"add_comment": "/members/addComment",
"load_status": "/api/loadStatus"
}
}
var common = {
pager: 1,
page: 0,
data: {
saved: {},
save: function (k, v) {
this.saved[k] = v;
}
},
ajax: {
callback: '',
type: 'POST',
url: '',
dataType: '',
data: {},
add: function (k, val) {
this.data[k] = val;
},
clear: function () {
this.data = {};
},
send: function () {
var ret;
$.ajax({
type: this.type,
url: this.url,
data: this.data,
dataType: this.dataType !== '' ? this.dataType : "json",
success: function (msg) {
if (common.ajax.callback !== '') {
ret = msg;
common.ajax.callback(ret);
} else {
ret = msg;
return ret;
}
return;
},
error: function (response) {
console.log(response);
alert("Error");
}
})
}
}
var callback = function (results) {
console.log(results
}
common.ajax.callback = callback;
common.ajax.type = "jsonp";
common.ajax.type = "POST";
common.ajax.url = controller_wrapper.controller.perpage;
common.ajax.add("offset", common.page);
common.ajax.add("type", $("select[name='query[type]']").val());
common.ajax.add("max", $("select[name='query[max]']").val());
common.ajax.add("min", $("select[name='query[min]']").val());
common.ajax.add("bedrooms", $("select[name='query[bedrooms]']").val());
common.ajax.add("sort", $("select[name='query[sort]']").val());
common.ajax.send();

Categories

Resources