backbone sync callback always use error - javascript

I am having a hard time figuring out how to get the callback to work correctly when using Backbone sync. I am looking at my return packets and the response code is 200 which is no error, yet the alert("fail") statement gets called. I am requesting a response from a java servlet. Any idea guys? Thanks
Backbone.sync("read", this.model, {
url : "some url",
success: function(model, response) {
alert(response);
},
error: function(model, response) {
alert("fail");
}
});

I don't understand what you are doing...
Use this methods instead of sync:
model.fetch();
model.save();
model.destroy();
They will call sync, and they work perfectly.
I don't think it's necessary to override the original sync, it is good enough. I created a mock sync for an example application, this is how it works:
var User = Backbone.Model.extend({
notAllowedEmailHost: "gmail.com",
sync: function (method, model, options) {
if (method == "read" || method == "delete")
throw new Error("Example is not prepared for these methods.");
var email = model.get("email");
var status = 201;
if (email.indexOf(this.notAllowedEmailHost) != -1)
status = 400;
else if (method == "update")
status = 500;
options.xhr = {
status: status
};
if (status >= 400)
options.error(options.xhr);
else
options.success({
id: 1
});
}
});
The methods above create wrapper functions around your callbacks, and in sync those wrappers are called with the result. So the callback in sync is not the callback you give by the call of fetch, save or destroy functions...

Make sure that your servlet returns a JSON object, even if it's empty. This fixed the issue in my case.

Related

Javascript: ajax trouble with requests arrays

I'm fairly new to javascript and I'm still trying to grasp callback concepts. Even then, I'm not sure I have an issue with callbacks or ajax itself.
So I have this callback function which basically takes an array of objects somewhere else in my code.
function powerAmplifierInfo(id, cb) {
ApiGet('/system/radio-frequency/tx/' + id + '/power-amplifier', function (err, result) {
if (err && !TESTING) {
alertError("Connection error: " + err.statusText);
return;
} else if (result && result.result.code !== "OK") {
alertError(result.result.message);
return;
}
if (TESTING) {
result = { powerAmplifier: "TEST model", uptime: Date.now() };
}
cb(result.powerAmplifier);
});
}
This function uses another function which uses ajax to send a get request to some server.
function ApiGet(urlSuffix, cb) {
var url = apiPrefix + "/" + urlSuffix;
$.ajax({
url: url,
type: 'GET',
success: function (result) {
cb(null, result);
},
error: function (err) {
cb(err, null);
}
});
}
Now, the request chains in my list works but sometimes requests get mixed up together when I rerun the code in loop as it seems ajax switch some port orders while sending requests. I found out this issue while troubleshooting my local network with Wireshark. Here's an image to show it:
The Get requests are sent but between the 3rd and the 4th ones, there is a port mixup. As we can see, the server replies without the port order mixup.
I'm wondering, is this a known issue or would there be a problem with my code, or even my server? I do not get this error when sending a single object in my callback functions instead of an object array.
Thanks in advance!

How to fire an error when overriding Backbone's the "parse" method

I am trying to throw an error when the server response I receive within the parse() method is not valid.
I tried setting the error key in the options parameter to false or call the options.xhr.error(this, resp, options); method within my overidden parse() method of my model, but none of them causing the error callback of the fetch() method to trigger.
Any clue?
Here the actual example:
Backbone.Model.extend({
parse: function parse(resp, options){
if(resp && resp.meta.success){
return resp.response;
}else{
//Throw an error which cause the "error" callback of the fetch method to get triggered
}
}
an});
You should be able to override the sync function to trigger the error callback if the response has an error, or call the default success handler with the main response:
var MyModel = Backbone.Model.extend({
sync: function(method, model, options){
var error = options.error;
var success = options.success;
options.success = function(resp){
if (resp && resp.meta.success){
success(resp.response);
} else{
error(resp.response);
}
};
return MyModel.__super__.sync.call(this, method, model, options);
}
});

Fetch data on different server with backbone.js

I can't see what the problem with this is.
I'm trying to fetch data on a different server, the url within the collection is correct but returns a 404 error. When trying to fetch the data the error function is triggered and no data is returned. The php script that returns the data works and gives me the output as expected. Can anyone see what's wrong with my code?
Thanks in advance :)
// function within view to fetch data
fetchData: function()
{
console.log('fetchData')
// Assign scope.
var $this = this;
// Set the colletion.
this.collection = new BookmarkCollection();
console.log(this.collection)
// Call server to get data.
this.collection.fetch(
{
cache: false,
success: function(collection, response)
{
console.log(collection)
// If there are no errors.
if (!collection.errors)
{
// Set JSON of collection to global variable.
app.userBookmarks = collection.toJSON();
// $this.loaded=true;
// Call function to render view.
$this.render();
}
// END if.
},
error: function(collection, response)
{
console.log('fetchData error')
console.log(collection)
console.log(response)
}
});
},
// end of function
Model and collection:
BookmarkModel = Backbone.Model.extend(
{
idAttribute: 'lineNavRef'
});
BookmarkCollection = Backbone.Collection.extend(
{
model: BookmarkModel,
//urlRoot: 'data/getBookmarks.php',
urlRoot: 'http://' + app.Domain + ':' + app.serverPort + '/data/getBookmarks.php?fromCrm=true',
url: function()
{
console.log(this.urlRoot)
return this.urlRoot;
},
parse: function (data, xhr)
{
console.log(data)
// Default error status.
this.errors = false;
if (data.responseCode < 1 || data.errorCode < 1)
{
this.errors = true;
}
return data;
}
});
You can make the requests using JSONP (read about here: http://en.wikipedia.org/wiki/JSONP).
To achive it using Backbone, simply do this:
var collection = new MyCollection();
collection.fetch({ dataType: 'jsonp' });
You backend must ready to do this. The server will receive a callback name generated by jQuery, passed on the query string. So the server must respond:
name_of_callback_fuction_generated({ YOUR DATA HERE });
Hope I've helped.
This is a cross domain request - no can do. Will need to use a local script and use curl to access the one on the other domain.

Prototype validation not working correctly

I use Prototype.js to validate a form. For one of the fields, I have the prototype script ajax a request to a file. The file is a simple PHP file and will return '1' if the value is OK and '0' if the value is not OK. I have the script as below, which should work perfectly. The prototype validation is supposed to show a validation error message when a field does not pass validation, and not display / remove the message once the field passes validation. But in this case, even when the ajax file returns '1', the validation will display the error message anyway. Anyone able to help would be greatly appreciated!
['validate-number3', numessage3, function(v) {
new Ajax.Request('test.php?nr='+v, {
method:'get',
onSuccess: function(transport) {
var response = transport.responseText;
if(response == '1'){return true;}else{return false};
}
});
}],
the return value from Ajax.Request is the Ajax.Request object and returns as soon as the request is setup - the onsuccess callback is called after the request has been completed - so checking the results of Ajax.Request is not useful for what you want to accomplish.
The reason that this doesn't work as you expect, this is an asynchronous call which means it will start the call and then return control to the script while it is processing and then run the callbacks when it is completed.
Try it this way
new Ajax.Request('test.php?nr='+v, {
method:'get',
onSuccess: handleResponse
});
function handleResponse( transport ){
var response = transport.responseText;
if(response == '1'){
//everything is OK
}else{
//value is not OK
};
}
I was able to solve my question!
Thanks to this teriffic page: http://inchoo.net/ecommerce/magento/magento-frontend/magento-form-field-ajax-validation/ it was no problem. This is what I ended up with:
var ok = false;
new Ajax.Request('test.php?nr='+v, {
method:'get',
asynchronous: false,
onSuccess: function(transport) {
var response = transport.responseText;
if(response == '1'){ok = true;}else{ok = false;};
},
onComplete: function() {
if ($('advice-validate-number-pay_bank_no')) {
$('advice-validate-number-pay_bank_no').remove();
}
}
});
return ok;

AngularJS navigation by HTTP status code. (MVC design)

I’m trying the convert an unstructured jQuery application to MVC AngularJS but at one point I’m kind of lost or I just don’t get it… (Unfortunately I’m not a JavaScript-God so the error might also be there)
This is the snippet of the original jQuery code.
$.ajax({
type: "GET",
url: "rest/users/" + userId + "/requests",
accept: "application/json; charset=utf-8",
statusCode: {
200: function(data) {
// do something
},
404: function() {
window.location = 'index.html';
},
500: function() {
alert("Server Error!");
}
}
});
A simple REST call where the HTTP response code is used to navigate. Unfortunately I can’t make this run in AnglularJS.
Here is my Controller:
// Inside the RequestController
$scope.requests = RequestModel.getRequestsByUser($rootScope.currentUser.userId);
if($scope.requests.statusCode == 200) {
// do something
}
else if($scope.requests.statusCode == 404) {
$location.path('/notFound');
} else if ($scope.requests.statusCode == 500) {
$location.path('/error');
}; // PROBLEM: The if/else statement is never true since statusCode is not available
Here is my Model:
// Inside the RequestModel
this.getRequestsByUser = function(userId) {
var RequestResource = $resource('../rest/users/' + userId + "/requests");
var requestList = RequestResource.get({}, function(response, getResponseHeaders) {
// PROBLEM: The property "stausCode" is "unavilable" at the Controller even if it was set here
requestList.statusCode = 200;
console.log("SUCCESS: getRequestsByUser() -> StatusCode: requestList.statusCode");
console.log(requestList);
}, function(response, getResponseHeaders) {
requestList.statusCode = response.status;
console.log("FAILED: getRequestsByUser() -> StatusCode: " + response.status);
});
return requestList;
};
This doesn't work since “statusCode” is “unavailable” inside my controller. The REST call works and also the data binding to the view is fine. I’m just not able to implement the “navigation part”. Do I miss something like $watch properties, asynchronous behavior or is my approach just incorrect?!
Thanks for your help!
You can make better use of resource parameter mapping in your service:
// Inside service
this.requestsByUser = $resource('../rest/users/:userId/requests', {userId:'#userId'});
That way you'll be able to reuse the same resource for different rest actions (eg. post, delete).
And controller code to handle statuses (response handlers were moved to controller):
// Inside the RequestController
$scope.requests = RequestModel.requestsByUser
.get(
{userId: $rootScope.currentUser.userId},
function(response) { // success handler
if(response.status == 200) {
// do something
}
},
function(response) { // error handler
if(response.status == 404) {
$location.path('/notFound');
} else if (response.status == 500) {
$location.path('/error');
}
}
);
Another way around is to use $q service to return promises from your service. But provided solutions seems cleaner to me

Categories