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.
sync and fail aren't valid callbacks. fetch uses the standard jQuery XHR object's options; there's success, error, and complete.
Here's a demo:
http://jsfiddle.net/ccamarat/sGJy4/
Related
I am new to javascript, callback functions and select2. Thanks in advance for your help :)
I am looking at implementing select2 to search against an API but I will have to use axios instead of the default jQuery method. Below is my code. I am able to send and retrieve results but I am not sure how to use the success callback.
I get "TypeError: success is not a function"
$("#profile-select").select2({
ajax: {
transport: function(params, success, failure){
axios.post("/rest/vue/1.0/profile/search", {query: $("#profile-select").val()})
.then(function(response){
success(response);
})
.catch(function(error){
alert(error);
});
},
processResults: function(data){
var processedArray = [];
data.profiles.forEach(function(item){
processedArray.push({id: item.ID, text: item.name});
});
return processedArray;
}
},
minimumInputLength: 2,
placeholder: "Select a profile",
allowClear: true
});
Questions
How do I return the response data to processResults in the .then function on the axios request? The documentation is at https://select2.org/data-sources/ajax
What is the best way to pass the input from the select list to the post request? Currently I am using jQuery.val() function which doesn't seem to work.
You can create callback functions just like any other functions.
For example:
function success(response) {
//do with response data what's necessary
}
Callback means that you pass this function as parameter for later execution.
When you create select2 ajax transport, then you pass your function name as parameter (as callback function).
When code execution meets line "success(response);" then your success function is actually executed.
This is my example using laravel as backend. The param success in transport is a callback for processResults method. Use data function to get the value from the input.
{
// [..]
ajax: {
url : 'yourUrl',
data: function (params) {
let query = {
term: params.term, // Get value form input
page: params.page || 1
}
return query;
},
transport: function(params, success, failure){
axios.get(this.url, { params : this.data } )
.then(function(data){
success(data);
})
.catch(function(error){
console.log(error);
});
},
processResults: function (response, params) {
// params.page = params.page || 1;
return {
results: response.data.data,
pagination: {
more: response.data.links.next ? true : false,
}
};
},
},
}
My application has a lot of AJAX calls, each of them return a JSON response. Instead of validating the data in each of the the .done() calls, I'm trying compact the code.
What we have so far
$.ajax({
url: 'test',
type: 'GET',
data: {
_token: token
},
dataFilter: function(jsonResponse) {
return isValidJson(jsonResponse);
}
}).done(function(jsonResponse) {
// do things
});
isValidJson(jsonResponse) {
try {
var parsedJson = $.parseJSON(jsonResponse);
if (parsedJson.error == 1) {
notificationController.handleNotification(parsedJson.message, 'error');
return false;
}
} catch (err) {
notificationController.handleNotification('A server-side error occured. Try refreshing if the problem persists.', 'error');
return false;
}
return jsonResponse; // Have to return the original data not true
}
The expected behavior is that if dataFilter returns false, it will trigger .fail(), if it returns true then it will continue to .done(). Instead, it just continues to .done() with the result of isValidJson().
Is there also a way to make .fail() do something standard like send a notification to the user without having to put it under every AJAX call?
Easiest way is to create a shorthand for $.ajax, by extending it.
Extending the AJAX call
jQuery.extend({
myAjax: function(params){
// Here we can modify the parameters and override them e.g. making 'error:' do something different
// If we want to add a default 'error:' callback
params.error = function() {
console.log('its failed');
};
// or you can specify data parse here
if (params.success && typeof params.success == 'function') {
var successCallback = params.success;
var ourCallback = function(responseJson) {
if (isValidJson(responseJson)) { // Validate the data
console.log('The json is valid');
successCallback(responseJson); // Continue to function
} else {
console.log('The json is not valid');
}
}
params.success = ourCallback;
}
return $.ajax(params);
}
});
Now everytime you want to make an AJAX call in your application, you DO NOT use $.ajax({}). Instead, you use $.myAjax({});
Example
$.myAjax({
url: 'domain.com',
type: 'GET',
success: function(data) {
// Do what you'd do normally, the data here is definitely JSON.
},
error: function(data) {}
});
And this special function will handle all errors same way, no need to write those validators every time.
Try to do it like this (Not tested):
var jxhr = $.ajax({
url: 'test',
type: 'GET',
data: {
_token: token
},
dataFilter: function(jsonResponse) {
if (!isValidJson(jsonResponse)) {
jxhr.abort();
}
return jsonResponse;
}
}).done(function(jsonResponse) {
// do things
});
By using this strategy - you are violating "separation of concern" strategy.
Ajax should resolve or reject according to its action. Not according if response is JSON or not.
A possible solution : ( sure there are also another solutions)
function GetSanitized(d) {
return d.then(function(a) {
if (a.indexOf('{') > -1) //check if json ( just for example)
return $.Deferred().resolve(JSON.parse(a)); //return object
else
return $.Deferred().reject(a); //reject
},
function() {
return $.Deferred().reject("ajax error"); //ajax failed
}
);
}
var ajax = $.Deferred();
GetSanitized(ajax) .then(function (a){alert(" Json p's value is "+a["p"]);},function (a){alert("Error"+a);});
ajax.resolve("{\"p\":2}"); //simulate ajax ok , valid json
//ajax.resolve("\"p\":2}"); //simulate ajax ok , invalid json
//ajax.reject("\"p\":2}"); //simulate ajax bad , valid json
http://jsbin.com/vozoqonuda/2/edit
I'm using backbone to post a login form to my server. After it queries the database it will flip a boolean value allowing me to retrieve GET responses from the server. The problem is that it tries to fetch (i think) before my login is validated. Given this code:
App.Login.add(newContact);
var out = newContact.save();
App.Contacts.fetch();
How do i write a callback to have it first finish newContact.save() before fetching Contacts?
This is what I have so far, but it never succeeds:
login: function(event) {
App.Browser.navigate('contacts');
event.preventDefault();
var $form = this.$('.login form');
var newContact = new App.Models.Login({
userName: $('input.userName', $form).val(),
passWord: $('input.passWord', $form).val(),
});
App.Login.add(newContact);
newContact.save({userName:"Frank"},{
wait: true,
success: function(model, response){
console.log('success');
},
error: function(){
console.log('error');
}
});
Model.save() accept callback to handle success or failure . which the code like:
App.Login.add(newContact);
var out=newContact.save(attributes,{
wait: true,// wait for the sever response finish
success:function(model, response,options){
App.Contacts.fetch();
},
error:function(model, xhr, options){
app.error(model);//custom handle for error
}
});
If I have to leverage niceties of jQuery AJAX API and set my own custom settings for each ajax call my app makes like below:
Say I have a page which displays employee information within table by making ajax calls to some API.
define(["jQuery"], function($) {
var infoTable = function (options) {
function init() {
// Provide success callback
options.success_callback = "renderData";
getData();
}
function renderData() {
// This callback function won't be called as it is not
// in global scope and instead $.ajax will try to look
// for function named 'renderData' in global scope.
// How do I pass callbacks defined within requirejs define blocks?
}
function getData() {
$.ajax({
url: options.apiURL,
dataType: options.format,
data: {
format: options.format,
APIKey: options.APIKey,
source: options.source,
sourceData: options.sourceData,
count: options.count,
authMode: options.authMode
},
method: options.method,
jsonpCallback: options.jsonpCallback,
success: options.success_callback,
error: options.error_callback,
timeout: options.timeout
});
}
}
return {
init: init
}
}
How do I achieve this?
I know we can use JSONP request as require calls but that restricts me to using jsonp, making GET requests and all other features $.ajax offers.
This example would let you either use a default success callback, or provide an override, using:
success: options.successCallback || renderData
(The example uses jsfiddle rest URLs - this fact is unimportant, and stripped out the data object to keep the example short)
define("mymodule", ["jquery"], function($) {
function renderData() {
console.log("inside callback");
}
function getData(options) {
$.ajax({
url: options.apiURL,
dataType: options.format,
method: options.method,
jsonpCallback: options.jsonpCallback,
success: options.successCallback || renderData,
error: null,
timeout: options.timeout
});
}
return {
getData: getData
}
});
require(["mymodule"], function(m) {
console.log(m, m.getData({
apiURL: "/echo/json/"
}));
console.log(m, m.getData({
successCallback: function() { console.log("outside callback"); },
apiURL: "/echo/json/"
}));
});
Would print:
GET http://fiddle.jshell.net/echo/json/ 200 OK 263ms
Object { getData=getData()} undefined
GET http://fiddle.jshell.net/echo/json/ 200 OK 160ms
Object { getData=getData()} undefined
inside callback
outside callback
I have a custom sync method in my backbone.js app. All my models call this method, but since I override success in this method, my success methods from the individual models are no longer being called. Here's what I mean - Below is my custom sync method:
app.customSync = function(method, model, options) {
var success = options.success,
error = options.error,
customSuccess = function(resp, status, xhr) {
//call original, trigger custom event
if(con)console.log('in custom success');
success(resp, status, xhr);
},
customError = function(resp, status, xhr) {
if(con)console.log('in custom error');
error(resp, status, xhr);
};
options.success = customSuccess;
options.error = customError;
Backbone.sync(method, model, options);
};
Backbone.Model.prototype.sync = app.customSync;
Here is an example me trying to call success from a model save:
this.model.save({
success:function(model, response){
if(con)console.log('this is never called');
}
});
Does anyone know how I can still the custom sync with the custom success methods, and call success from my individual saves?
As a side note, I tried calling success msuccess in the model.save, but the msuccess was undefined in the custom sync.
The first argument to Model.save is a hash of attributes you wish to modify, the options come second and hold the success/error callbacks.
Try
this.model.save({}, {
success: function() {
console.log('save success');
}
});
And a Fiddle to see this at work http://jsfiddle.net/nikoshr/XwfTB/