How to use requirejs to work with ajax callbacks? - javascript

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

Related

How to call external method from nested ajax (success) method?

I need to call onSuccessLogin method from ajax success method, or put response as argument into onSuccessLogin.
Thank you for answers.
submit: function (form) {
$.ajax({
type: "post",
url: "/login",
data: {
login: $(form).find('#login').val(),
password: $(form).find('#password').val(),
deviceType: environmentInfo.browser,
sdkVersion: environmentInfo.browserVersion,
osVersion: environmentInfo.OS
},
success: function(res) {
localStorage.setItem("languagesList", res);
//how to call onSuccessLogin method from here?
},
//Another implementation
// success: this.onSuccessLogin(res), - dosen't work, if I want put response from ajax into this method call
error: this.onErrorLogin
});
},
onSuccessLogin: function () {
//localStorage.setItem("languagesList", res); get response from second implementation
window.location = "/";
}
By creating a reference (that can be seen from the scope of AJAX success callback) to the object holding onSuccessLogin.
Inside the submit method (as a sibling of onSuccessLogin) that object is this.
Also see MDN reference on ES6 Arrow functions - abstraction for binding this to enclosing scope.
submit: function (form) {
var self = this;
$.ajax({
type: "post",
url: "/login",
data: {
login: $(form).find('#login').val(),
password: $(form).find('#password').val(),
deviceType: environmentInfo.browser,
sdkVersion: environmentInfo.browserVersion,
osVersion: environmentInfo.OS
},
success: function(res) {
localStorage.setItem("languagesList", res);
self.onSuccessLogin();
},
//Another implementation
// success: this.onSuccessLogin(res), - dosen't work, if I want put response from ajax into this method call
error: this.onErrorLogin
});
},
onSuccessLogin: function () {
//localStorage.setItem("languagesList", res); get response from second implementation
window.location = "/";
}
I don't know this logic is correct or not , if you place the function outside of ajax loop it will work .
$.ajax({
url: 'test',
success: function(data) {
alert("received contents="+data);
onSuccessLogin();
}
});
function onSuccessLogin() {
alert("Successfully logged!!!");
}

Ajax request to return module setup data

I have looked at various questions that talk about when Synchronous requests, how to return data from the Ajax request (with Promises and Callbacks) but nothing seems to answer what I am after.
var FacadeApi = ( function($) {
var endpoint = '/auth/',
self = this,
settings = {
isAuthenticated: false,
authkey: null
};
function init() {
$.ajax( {
url: self.endpoint,
dataType: 'json',
async: true
})
.done( function( `enter code here`data ) {
self.settings.authKey = data.authKey;
self.settings.isAuthenticated = true;
})
.fail( function( error ) {
});
}
var Facade = {
someRequest: function( ) {
$.ajax( {
url: someUri,
dataType: 'json',
data: { authKey: authKey }
})
.done( fuction( data ) {
// does stuff.
});
}
};
init();
return Facade;
}( jQuery ));
My module depends on requesting an authentication key and then having that as part of each request. Until this request is resolved, it can't be used. Which lead me to the async: false in the init function.
In this scenario, is it recommended to 'block' until the init call is completed? Could I achieve what I am after and keep the init request asynchronous?
So if i understand correctly,
You want to make sure that if someone calls somerequest() it should wait till you have the token , which is initiated in a separate request.
I suggest following pattern.
Do not call init() from the beginning.
when you need to call somerequest()
check if you have valid token value.
If token value is not there you can use $.When() such that somerequest() is only called when init() ajax call returns successfully.

JavaScript Scoping - Passing callback to already defined function

The title is a bit weird, don't quite know the best way to explain it in a sentence...
At present there is an object with 3 functions; func, funcSuccess, and funcFailure. func contains a jQuery ajax request, with this.funcSuccess as the success callback, and funcError as the error callback. func is passed a callback for any success values to be passed back to, however this callback needs to be executed in the funcSuccess code.
Here's the code:
var Obj =
{ func: function (callback) {
$.ajax(
{ type: 'POST'
, url: '/func'
, success: this.funcSuccess
, error: this.funcError
}
)
}
, funcSuccess: function (res) {
// THIS IS WHERE CALLBACK IS NEEDED
callback(res.thing)
}
, funcError: function (res) {
debug(res)
}
}
I'm wondering if there's a tidier way to do it rather than having:
var that = this
$.ajax(
{ type: 'POST'
, url: '/func'
, success: function (res) {
that.funcSuccess(res)
}
, error: this.funcError
}
)
Pretty sure I'm missing something obvious, just not quite with it today...
What about storing the callback explicitly in your object, so you don't have to worry about closure scopes:
var Obj =
{ func: function (callback) {
//this.callback = callback;
$.ajax(
{ type: 'POST'
, url: '/func'
, success: $.proxy(this.funcSuccess, this, callback)
, error: $.proxy(this.funcError, this)
}
)
}
, funcSuccess: function (callback, res) {
callback(res.thing)
}
, funcError: function (res) {
debug(res)
}
}
Edit: I forgot to bind the callbacks to this. In JQuery you can do it with $.proxy, see changes above.
Edit: A further tidy (jQuery 1.6 allows for this) with passing the callback as an argument to $.proxy, so no need to attach it to the current object.
You need to pass the callback into the funcSucess, else it won't have access to it. Here by using a closure:
var Obj = {
func: function (callback) {
return $.ajax({
type: 'POST',
url: '/func',
success: this.makeFuncSuccess(callback),
error: this.funcError
});
}, makeFuncSuccess(callback) {
return function funcSuccess (res) {
callback(res.thing);
};
},
funcError: function (res) {
debug(res)
}
};

Triggering a Javascript callback after a completed ajax call within an object

I'm trying to trigger an action after a Javascript object has been created via an AJAX call. My object looks something like this:
function API(uid,accessToken){
$.ajax("path/to/file", {
type: "POST",
data: { user: uid, auth: accessToken },
dataType: "json",
success: function(jsonData) {
arrayname = jsonData[values]
}
});
}
I tried to use JQuery's $.when function to do a callback after the object setup is complete (ie. the array is populated with the ajax response), which looked like this:
$.when( API = new API(uid, accessToken) ).then(function() {
...success function...
});
...but the $.when function triggers with the arrayname values still undefined. From the function's standpoint the deferred object is resolved even though the object values have not yet been set. I've since tried a number of ways to make the API object become deferred based on the completing of the entire ajax call and the setting of the variables, but I'm a bit stuck on the best way to do this.
Any pointers would be most appreciated! Thanks.
You could pass the callback function when you create the object, like so:
function API(uid,accessToken, callback){
$.ajax("path/to/file", {
type: "POST",
data: { user: uid, auth: accessToken },
dataType: "json",
success: function(jsonData) {
arrayname = jsonData[values]
callback(jsonData[values])
}
});
}
and then instantiate the object like so
var api = new API(uid, accessToken, function(array) {
// success function
});
If the problem is due to the "success" callback running after the "then" callbacks, you could try turning success callback into a then callback as well. I don't use JQuery but I guess it would look something like:
function API(uid,accessToken){
return $.ajax("path/to/file", {
type: "POST",
data: { user: uid, auth: accessToken },
dataType: "json",
}).then(function(jsondata){
arrayname = jsondata[values]
});
}
$.when( API = new API(uid, accessToken) ).then(function() {
// ...
});
The reason you use $.when is when you are correlating the callbacks of multiple promises, async tasks, etc. Since jQuery 1.5, all calls to $.ajax and all the wrappers ($.get and $.post) all return promises. Therefore you don't need to wrap this call with the $.when statement unless you want to do $.when(ajaxCall1, ajaxCall2).
Since you want to filter the result from the server, you should use the pipe method of promises:
function API(uid, accessToken)
return $.post(
type: 'POST'
,data: { user: uid, auth: accessToken }
,dataType: 'json'
)
.pipe(function(json) {
return json[values];
})
;
}
This allows you to write your code the way you desire:
API(uid, token)
.then(
// success state (same as promise.done)
function(arrayname /* named from your sample script*/) {
alert('success! ' + arrayname);
}
// error state (same as promise.fail)
,function(jqXHR, status, error) {
console.warn('oh noes!', error);
}
)
.done(function() { /* done #2 */ })
.fail(function() { /* fail #2 */ })
;
Note: promise.pipe() also allows you to filter (change the data passed to) the error callback as well.

jQuery's AJAX call to a javascript class method

I'm a newbee about jQuery's workflow and I would like to setup a javascript class that uses an internal method to make an AJAX request. When the request returns with success, the jQuery AJAX callback should invoke a method owned by the class itself. That's the code:
function IXClock()
{
this.m_intervalID = 0;
this.startClock = function ()
{
this.m_intervalID = setInterval(this.tictac, 500);
}
this.stopClock = function ()
{
clearInterval(this.m_intervalID);
}
this.setClockTime = function(p_strTime)
{
$('#clock').html(p_strTime);
}
this.tictac = function ()
{
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: function (data)
{
this.setClockTime(data);
}
});
}
}
The class represents a clock, with an internal method (tictac) that requests "what's the time" on the server side.
After the server says the time, the jQuery's AJAX method should invoke the setClockTime method of the IXClock class. The invoke method will update the #clock div item in the html page.
The problem is that the method this.setClockTime() results unknown and the javascript return the "this.setClockTime is not a function" error.
The question is: is there a way to invoka a class method from the jQuery's AJAX callback ?
I think that the problem is that the this in your callback function is different from the this referring to IXClock. Try:
var thisClass = this ;
this.tictac = function ()
{
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: function (data)
{
thisClass.setClockTime(data);
}
});
}
Test Case (added to site which already has jQuery loaded):
function uClass () {
this.testFunction = function(input) {
alert(input) ;
}
this.ajaxFunction = function() {
var myClass = this ;
$.ajax({
type: 'POST',
url: '/',
complete: function(data) {
alert(myClass.testFunction) ;
myClass.testFunction(data) ;
this.testFunction(data) ;
}
}) ;
}
}
var k = new uClass() ;
k.ajaxFunction() ;
It happens bacause your callback function leave in global context.
You can choose 2 ways
Use .bind function to bind context to callback function http://www.robertsosinski.com/2009/04/28/binding-scope-in-javascript/
jQuery's AJAX supports transfer some data to callback function. You can write smth like this:
:
this.tictac = function () { $.ajax ({ type: 'POST', context:this, url: '/rap/rapClock.php', complete: function (data) { this.setClockTime(data); } }); }
}
this does not refer to IXClock in your ajax callback. this allways points to the current scope (have a look at this document). You need to do something like this:
this.prototype.tictac = function ()
{
var self = this;
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: function (data)
{
self.setClockTime(data);
}
});
}
You can also use jQuery's .proxy()-function for this purpose:
this.prototype.tictac = function ()
{
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: $.proxy(function (data) {
this.setClockTime(data);
}, this)
});
}
The this in the result handler is not what you expect it is. (It is not the IXClock instance)
function IXClock()
{
this.m_intervalID = 0;
}
IXClock.prototype = {
startClock: function ()
{
this.m_intervalID = setInterval(this.tictac, 500);
},
stopClock: function ()
{
clearInterval(this.m_intervalID);
},
setClockTime: function(p_strTime)
{
$('#clock').html(p_strTime);
},
tictac: function ()
{
var that = this;
$.ajax({
type: 'POST',
url: '/rap/rapClock.php',
success: function (data) { // You want success here, not complete, IMO
that.setClockTime(data);
}
});
}
}
If you ask me, that ajax call is doing evil. It does not seem to send any data, nor modify any
state on the server, but is expecting/getting/using data from the php, yet is using the POST method.
Should've been
$.get('/rap/rapClock.php', function (data) {
that.setClockTime(data);
});
One simple solution is, to keep your callback function as self = this. This will support inheritance also.
class Record{
get_data(){
self = this;
$.ajax({
type : "GET",
url : "/get_url",
dataType : "json",
contentType: "application/json; charset=utf-8",
data : {},
success : function(data){
console.log(data);
self.load_table(data);
},
});
}
static load_table(data){
console.log(data);
}

Categories