Facing issue in using $.when().then() function - javascript

I need to make sure that getValue() is called only after execution of SetValueForVariable(). I cannot modify BindValue() or SetValueForVariable().
I tried $.when(BindValue()).then(getValue());. (As i cannot change the already existing flow)
It works some times but sometimes it shows the previously set value.
I need to call getValue on $(document).ready(). How do I make sure getValue() is only called after execution of SetValueForVariable().
//This function is inturn making call to SetValueForVariable() which is written in another file
//Cannot Change this
function BindValue() {
SetValueForVariable()
}
function getValue()
{
$.ajax({
url: getRoutePath("GetPath/GetPath1"),
type: "GET",
async: true,
success: function (data) {
debugger;
data = JSON.parse(data)
$('#txtBox').text(data.Count);
});
}
//Written in another file
//Cannot change this function
function SetValueForVariable() {
//this fucntion is making server call the server method sets value of a Session Variable
$.ajax({
url: getRoutePath("SetPath/SetPath1"),
type: "GET",
async: true,
....
});
}

You could redefine BindValue, calling the original BindValue in your new definition after ensuring that getValue has been called.
Pseudo code
var originalBindValue = BindValue;
BindValue = function() {
if getValue has been called
originalBindValue();
else
call getValue and then originalBindValue() in getValue success / failure callback
}
I think this would work around your cannot modify BindValue limitation - you don't actually need access to BindValue code here.

Related

Jquery passing a function to a function

OK, i need some help,
i have a function inside a jquery plugin
var LoadPage = function (page, location, func){
$.ajax({
url: page,
success: function(data){
$(location).html(data); //Insert data into location
func
return true
},
});
}
i want to use it like this
Loadpage(
"api/page.php",
"#div_id",
$("#calander td.clickable").click(function() {
var day = $(this).attr("calendar-day");
console.log("clicked TD" + day);
LoadPage('/api/view_event.php?d='+day, settings.eventContainer);
})
);
or
Loadpage(
"api/page.php",
"#div_id",
function() {
var day = $(this).attr("calendar-day");
console.log("clicked TD" + day);
LoadPage('/api/php/calander/view_event.php?d='+day+'&m='+SelectedMonth+'&y='+SelectedYear, settings.eventContainer);
}
);
and then have it run that in the success: where var func is in it but unsure how to get this to work. please help internet.
There are three separate issues in your code:
1) If you want to execute the callback func in your success handler, then you need to add parens () after it as in func() as that is javascript's method of signifying that you want to execute a function.
var LoadPage = function (page, location, func){
$.ajax({
url: page,
success: function(data){
$(location).html(data); //Insert data into location
// add parens here after func
func();
return true
},
});
}
If you want the func argument to be optional, you can test for it before executing it like this:
var LoadPage = function (page, location, func){
$.ajax({
url: page,
success: function(data){
$(location).html(data); //Insert data into location
// add parens here after func to actually execute it
if (func) func();
return true
},
});
}
2) Then, you need to change how you call LoadPage() to pass it an actual function reference like this:
Loadpage(
"api/page.php",
"#div_id",
function() {
$("#calander td.clickable").click(function() {
var day = $(this).attr("calendar-day");
console.log("clicked TD" + day);
LoadPage('/api/view_event.php?d='+day, settings.eventContainer);
})
})
);
What you were passing it was the result of executing the .click function which is a jQuery object, not a function. Instead, you can wrap that in an anonymous function so you're passing a reference to that function. This is the opposite of the func(). You don't want parens after what you pass because you want to pass a reference to a function, not the result of executing the function now.
So, to summarize these two issues:
The statement:
func
is just a reference to a function. It doesn't actually execute the function. It is useful when you want to pass a reference to a function which will then call it LATER.
The statement:
func()
executes the function immediately. If you pass func() as an argument, then it will execute immediately (parens always mean to execute it now) and then pass the return value of that function (which is not what you want here).
3) You may also want to understand that the return true statement in your success handler does NOTHING. Because the ajax function is asychronous, your LoadPage() function just starts the ajax function and then returns immediately. Sometime later, the internals of the ajax engine calls your success handler. That return statement returns back into the interior of that ajax engine. It does NOT return from your LoadPage() function since that has already long since completed and returned nothing.
4) Possible fourth issue. Every time you call LoadPage(), you are going to add a new click handler to whatever objects this selector matches: "#calander td.clickable". If some of those objects existed previously, you will end up with multiple click handlers. In that case, you would either want to use delegated event handling so you could just install the click handler once ahead of time or you would need to remove the exist click handlers before installing the new ones or you would need to isolate only the newly added objects and only call it on them. If all "#calander td.clickable" are replaced by the previous code, then this would not be a problem.
Try this:
var LoadPage = function (page, location, func){
$.ajax({
url: page,
success: function(data){
$(location).html(data); //Insert data into location
func && func(); // this will execute func if it is passed as parameter
return true;
}
});
}
And use it in the second way.

How do you write to a global function with JQuery and Ajax?

I want to return data from a AJAX handler into a global variable. I have tried making the call non asyc. The difficulty I am having is when I create a global variable and I make reference to that global variable the value becomes undefined outside the Ajax request. I have even tried calling a function using my success callback without any luck. Here is what it looks like at the moment. I made the call sync with a previous question being addressed jQuery ajax success callback function definition
config();
function config()
{
var dataBool;
var db_test;
$.ajax({asyc: false,
url: 'config.php',
dataType: "text",
data:{db_test:1},
type: "POST",
success: dataStuff
});
function dataStuff(data)
{
dataBool = data;
}
}
If you want dataBool to be a global variable... it needs to be a global variable, not a local variable
var dataBool;
config();
function config()
{
var db_test;
$.ajax({url: 'config.php',
dataType: "text",
data:{db_test:1},
type: "POST",
success: dataStuff
});
function dataStuff(data)
{
dataBool = data;
}
}
asyc: false is unnecessary and misspelled. The param is async:false, so that option had no effect, and you don't need it anyways.

Listen for a function to be called JavaScript

I have the following functions that is called every 2 seconds to load some data. It registers the function [do] to do the stuff with the response. (the example is simplified).
function doRequest (){
$.ajax({ url: 'www.google.com.pe', success: function (response) {do(response)} });
}
function do (text){
var i = setInterval(doRequest, 2000);
}
I wonder if there is any way that I can create a function that is called every time the [do] function is called with out needing to add a call to the listener inside the do function. If there is any better way to do it with jQuery, like a plugin I'd appreciate the help.
[Edit] The idea is not whether it works or not. My question was about if I can add a custom listener to the "do" function which was already implemented. Something like addActionListener("do", "after", doSomeThingElse),sSo I could do some thing else just after the do function has finished.
First, your simplified version won't work, because you'd need to pass the do function instead of calling it.
function doRequest (){
$.ajax({ url: 'www.google.com.pe', success: _do });
}
But it sounds like you're asking how to run some other code every time do is invoked.
If do is only invoked inside the doRequest() function, then just add your other code to an anonymous function that invokes do at the right time.
function doRequest (){
$.ajax({ url: 'www.google.com.pe', success: function(response) {
// Run your other code
// or invoke another function.
_do(response);
} });
}
If you want it to be more generalized, you can create a function decorator that returns a function which invokes do after some other code.
function doFactory(fn) {
return function() {
fn.apply(this, arguments);
_do.apply(this, arguments);
}
}
then make functions like this:
var doFoo = doFactory(function() {
console.log("foo");
});
If your requirement is more specific of a pre-processing of response, you could rework it like this:
function doFactory(fn) {
return function(response) {
_do.call(this, fn.call(this, response));
}
}
Then have the fn manipulate and return response.
var doFoo = doFactory(function(response) {
return response + "foo";
});
If you want to keep existing code as it is, you could wrap do() in another function which in turn calls do() and your new function (say do_this_as_well()).
See the example below (I renamed do() to do_this() to avoid confusion around the reserved keyword do). This works because global functions are nothing but variables with function objects in them. These variables can be overwritten, in this case with a new function that calls the old one:
function do_this(response) { ... }
(function()
{
var previous=do_this;
do_this=function(response) { previous(response); do_this_as_well(); }
})();
Replace
success: do(response)
with
success: function(response) { do(response); do_this_as_well(); }

javascript prototype access this

I have a javascript 'class' which contains a wrapper method to call jquery .ajax(). I want to pass in the onSuccess and onError function handlers, but am not sure how. I can do this with plain old global functions, but I'm trying to improve my javascript (from Java background). Any pointers would be appreciated.
In the _makeAjaxCall() method below, how do I reference the onSuccessHandler
function testApp() {
new X();
}
function X() {
// Init X by making Ajax call, passing the func to be called on ajax return
this._makeAjaxCall(initUrl, this.onSuccessInit, this.onError);
// Make another ajax call to init another component
this._makeAjaxCall(initUrl, this.onSuccessSomeOtherAjaxCall, this.onError);
}
X.prototype.onSuccessInit = function(){
this.doStuff(...);
}
X.prototype.onSuccessSomeOtherAjaxCall = function(){
this.doOtherStuff(...);
}
/**
* make an ajax call, and call the provided success/error handler
*/
X.prototype._makeAjaxCall = function(url, onSuccessHandler, onError){
$.ajax({
url : url,
success : function (jsonData, textStatus, XMLHttpRequest) {
// If I don't user 'this', the func called but I've lost my reference
// to my instance of X
onSuccessHandler();
// If I use 'this', it points to the ajax call object, not to my X object.
this.onSuccessHandler();
}
});
}
The problem is that when the success callback is called by the $.ajax function, the default context is used window. You need to tell JQuery that you want a different context, so you can do one of 3 things:
Add a context attribute to the hash that is sent to $.ajax, so I your case you can do:
$.ajax({
url: url,
context: this, // this will tell JQuery to use the right context
success: this.onSuccessHandler
});
Use JQuery's $.proxy function, like:
$.ajax({
url: url,
success: $.proxy(this.onSuccessHandler, this) // this will bind the correct context to the callback function
});
Cache the variable this, like #mVChr suggested, although I would encourage you to use self as it has become somewhat of a javascript idiom
var self = this;
$.ajax({
url: url,
success: function(data) {
self.onSuccessHandler(data);
}
});
Edit:
If you need a more in depth explanation of context and scope in javascript checkout this article: http://www.digital-web.com/articles/scope_in_javascript/
Cache this within the local scope of _makeAjaxCall before conducting the ajax call:
X.prototype._makeAjaxCall = function(url, onSuccessHandler, onError){
var _X = this; // cache this
$.ajax({
url : url,
success : function (jsonData, textStatus, XMLHttpRequest) {
// use cached this
_X.onSuccessHandler();
}
});
}
Thanks to input from CarlosZ & mVChr, I've figured out the solution, http://jsfiddle.net/bX35E/3/
$(document).ready(function testApp() {
new X();
});
function X() {
console.dir(this);
var initUrl = "/echo/json/";
this._instanceVariable = "I AM defined!";
// Init X by making Ajax call, passing the func to be called on ajax return
this._makeAjaxCall(initUrl, this.onSuccessInit(), this.onError);
// Make another ajax call to init another component
this._makeAjaxCall(initUrl, this.onSuccessSomeOtherAjaxCall(), this.onError);
}
X.prototype.onSuccessInit = function(){
//this.doStuff(...);
var self = this;
return function() {
alert("onSuccessInit, _instanceVariable="+self._instanceVariable);
}
}
X.prototype.onSuccessSomeOtherAjaxCall = function(){
var self = this;
return function() {
alert("onSuccessSomeOtherAjaxCall, _instanceVariable="+self._instanceVariable);
}
}

jQuery pass more parameters into callback

Is there a way to pass more data into a callback function in jQuery?
I have two functions and I want the callback to the $.post, for example, to pass in both the resulting data of the AJAX call, as well as a few custom arguments
function clicked() {
var myDiv = $("#my-div");
// ERROR: Says data not defined
$.post("someurl.php",someData,doSomething(data, myDiv),"json");
// ERROR: Would pass in myDiv as curData (wrong)
$.post("someurl.php",someData,doSomething(data, myDiv),"json");
}
function doSomething(curData, curDiv) {
}
I want to be able to pass in my own parameters to a callback, as well as the result returned from the AJAX call.
The solution is the binding of variables through closure.
As a more basic example, here is an example function that receives and calls a callback function, as well as an example callback function:
function callbackReceiver(callback) {
callback("Hello World");
}
function callback(value1, value2) {
console.log(value1, value2);
}
This calls the callback and supplies a single argument. Now you want to supply an additional argument, so you wrap the callback in closure.
callbackReceiver(callback); // "Hello World", undefined
callbackReceiver(function(value) {
callback(value, "Foo Bar"); // "Hello World", "Foo Bar"
});
Or, more simply using ES6 Arrow Functions:
callbackReceiver(value => callback(value, "Foo Bar")); // "Hello World", "Foo Bar"
As for your specific example, I haven't used the .post function in jQuery, but a quick scan of the documentation suggests the call back should be a function pointer with the following signature:
function callBack(data, textStatus, jqXHR) {};
Therefore I think the solution is as follows:
var doSomething = function(extraStuff) {
return function(data, textStatus, jqXHR) {
// do something with extraStuff
};
};
var clicked = function() {
var extraStuff = {
myParam1: 'foo',
myParam2: 'bar'
}; // an object / whatever extra params you wish to pass.
$.post("someurl.php", someData, doSomething(extraStuff), "json");
};
What is happening?
In the last line, doSomething(extraStuff) is invoked and the result of that invocation is a function pointer.
Because extraStuff is passed as an argument to doSomething it is within scope of the doSomething function.
When extraStuff is referenced in the returned anonymous inner function of doSomething it is bound by closure to the outer function's extraStuff argument. This is true even after doSomething has returned.
I haven't tested the above, but I've written very similar code in the last 24 hours and it works as I've described.
You can of course pass multiple variables instead of a single 'extraStuff' object depending on your personal preference/coding standards.
When using doSomething(data, myDiv), you actually call the function and do not make a reference to it.
You can either pass the doStomething function directly but you must ensure it has the correct signature.
If you want to keep doSomething the way it is, you can wrap its call in an anonymous function.
function clicked() {
var myDiv = $("#my-div");
$.post("someurl.php",someData, function(data){
doSomething(data, myDiv)
},"json");
}
function doSomething(curData, curDiv) {
...
}
Inside the anonymous function code, you can use the variables defined in the enclosing scope. This is the way Javascript scoping works.
It's actually easier than everyone's making it sound... especially if you use the $.ajax({}) base syntax vs. one of the helper functions.
Just pass in the key: value pair like you would on any object, when you setup your ajax request... (because $(this) hasn't changed context yet, it's still the trigger for the bind call above)
<script type="text/javascript">
$(".qty input").bind("keypress change", function() {
$.ajax({
url: "/order_items/change/"+$(this).attr("data-order-item-id")+"/qty:"+$(this).val()+"/returnas.json",
type: "POST",
dataType: "json",
qty_input: $(this),
anything_else_i_want_to_pass_in: "foo",
success: function(json_data, textStatus, jqXHR) {
/* here is the input, which triggered this AJAX request */
console.log(this.qty_input);
/* here is any other parameter you set when initializing the ajax method */
console.log(this.anything_else_i_want_to_pass_in);
}
});
});
</script>
One of the reasons this is better than setting the var, is that the var is global and as such, overwritable... if you have 2 things which can trigger ajax calls, you could in theory trigger them faster than ajax call responds, and you'd have the value for the second call passed into the first. Using this method, above, that wouldn't happen (and it's pretty simple to use too).
In today's world there is a another answer that is cleaner, and taken from another Stack Overflow answer:
function clicked()
{
var myDiv = $( "#my-div" );
$.post( "someurl.php", {"someData": someData}, $.proxy(doSomething, myDiv), "json" );
}
function doSomething( data )
{
// this will be equal to myDiv now. Thanks to jQuery.proxy().
var $myDiv = this;
// doing stuff.
...
}
Here's the original question and answer:
jQuery HOW TO?? pass additional parameters to success callback for $.ajax call?
You can also try something like the following:
function clicked() {
var myDiv = $("#my-div");
$.post("someurl.php",someData,function(data){
doSomething(data, myDiv);
},"json");
}
function doSomething(curData, curDiv) {
}
You can use a closure of JavaScript:
function wrapper( var1, var2,....) // put here your variables
{
return function( data, status)
{
//Handle here results of call
}
};
and when you can do:
$.post("someurl.php",data,wrapper(var1, var2, etc...),"html");
I've made a mistake in the last my post. This is working example for how to pass additional argument in callback function:
function custom_func(p1,p2) {
$.post(AJAX_FILE_PATH,{op:'dosomething',p1:p1},
function(data){
return function(){
alert(data);
alert(p2);
}(data,p2)
}
);
return false;
}
Let's go simple ! :)
$.ajax({
url: myUrl,
context: $this, // $this == Current $element
success: function(data) {
$.proxy(publicMethods.update, this)(data); // this == Current $element
}
});
A more general solution for sending asynchronous requests using the .ajax() jQuery API and closures to pass additional parameters to the callback function:
function sendRequest(method, url, content, callback) {
// additional data for the callback
var request = {
method: method,
url: url
};
$.ajax({
type: method,
url: url,
data: content
}).done(function(data, status, xhr) {
if (callback) callback(xhr.status, data, request);
}).fail(function(xhr, status) {
if (callback) callback(xhr.status, xhr.response, request);
});
};
For me, and other newbies who has just contacted with Javascript,
I think that the Closeure Solution is a little kind of too confusing.
While I found that, you can easilly pass as many parameters as you want to every ajax callback using jquery.
Here are two easier solutions.
First one, which #zeroasterisk has mentioned above, example:
var $items = $('.some_class');
$.each($items, function(key, item){
var url = 'http://request_with_params' + $(item).html();
$.ajax({
selfDom : $(item),
selfData : 'here is my self defined data',
url : url,
dataType : 'json',
success : function(data, code, jqXHR){
// in $.ajax callbacks,
// [this] keyword references to the options you gived to $.ajax
// if you had not specified the context of $.ajax callbacks.
// see http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings context
var $item = this.selfDom;
var selfdata = this.selfData;
$item.html( selfdata );
...
}
});
});
Second one, pass self-defined-datas by adding them into the XHR object
which exists in the whole ajax-request-response life span.
var $items = $('.some_class');
$.each($items, function(key, item){
var url = 'http://request_with_params' + $(item).html();
$.ajax({
url : url,
dataType : 'json',
beforeSend : function(XHR) {
// 为了便于回调,把当前的 jquery对象集存入本次 XHR
XHR.selfDom = $(item);
XHR.selfData = 'here is my self defined data';
},
success : function(data, code, jqXHR){
// jqXHR is a superset of the browser's native XHR object
var $item = jqXHR.selfDom;
var selfdata = jqXHR.selfData;
$item.html( selfdata );
...
}
});
});
As you can see these two solutions has a drawback that : you need write a little more code every time than just write:
$.get/post (url, data, successHandler);
Read more about $.ajax : http://api.jquery.com/jquery.ajax/
If someone still comes here, this is my take:
$('.selector').click(myCallbackFunction.bind({var1: 'hello', var2: 'world'}));
function myCallbackFunction(event) {
var passedArg1 = this.var1,
passedArg2 = this.var2
}
What happens here, after binding to the callback function, it will be available within the function as this.
This idea comes from how React uses the bind functionality.
$(document).on('click','[action=register]',function(){
registerSocket(registerJSON(),registerDone,second($(this)));
});
function registerSocket(dataFn,doneFn,second){
$.ajax({
type:'POST',
url: "http://localhost:8080/store/public/register",
contentType: "application/json; charset=utf-8",
dataType: "json",
data:dataFn
}).done ([doneFn,second])
.fail(function(err){
console.log("AJAX failed: " + JSON.stringify(err, null, 2));
});
}
function registerDone(data){
console.log(JSON.stringify(data));
}
function second(element){
console.log(element);
}
Secondary way :
function socketWithParam(url,dataFn,doneFn,param){
$.ajax({
type:'POST',
url:url,
contentType: "application/json; charset=utf-8",
headers: { 'Authorization': 'Bearer '+localStorage.getItem('jwt')},
data:dataFn
}).done(function(data){
doneFn(data,param);
})
.fail(function(err,status,xhr){
console.log("AJAX failed: " + JSON.stringify(err, null, 2));
});
}
$(document).on('click','[order-btn]',function(){
socketWithParam(url,fakeDataFn(),orderDetailDone,secondParam);
});
function orderDetailDone(data,param){
-- to do something --
}
actually, your code is not working because when you write:
$.post("someurl.php",someData,doSomething(data, myDiv),"json");
you place a function call as the third parameter rather than a function reference.
As an addendum to b01's answer, the second argument of $.proxy is often used to preserve the this reference. Additional arguments passed to $.proxy are partially applied to the function, pre-filling it with data. Note that any arguments $.post passes to the callback will be applied at the end, so doSomething should have those at the end of its argument list:
function clicked() {
var myDiv = $("#my-div");
var callback = $.proxy(doSomething, this, myDiv);
$.post("someurl.php",someData,callback,"json");
}
function doSomething(curDiv, curData) {
//"this" still refers to the same "this" as clicked()
var serverResponse = curData;
}
This approach also allows multiple arguments to be bound to the callback:
function clicked() {
var myDiv = $("#my-div");
var mySpan = $("#my-span");
var isActive = true;
var callback = $.proxy(doSomething, this, myDiv, mySpan, isActive);
$.post("someurl.php",someData,callback,"json");
}
function doSomething(curDiv, curSpan, curIsActive, curData) {
//"this" still refers to the same "this" as clicked()
var serverResponse = curData;
}

Categories