Calling a JavaScript Function Returned from an Ajax Response

Calling a JavaScript function returned from an Ajax response

I think to correctly interpret your question under this form: "OK, I'm already done with all the Ajax stuff; I just wish to know if the JavaScript function my Ajax callback inserted into the DIV is callable at any time from that moment on, that is, I do not want to call it contextually to the callback return".

OK, if you mean something like this the answer is yes, you can invoke your new code by that moment at any time during the page persistence within the browser, under the following conditions:

1) Your JavaScript code returned by Ajax callback must be syntactically OK;

2) Even if your function declaration is inserted into a <script> block within an existing <div> element, the browser won't know the new function exists, as the declaration code has never been executed. So, you must eval() your declaration code returned by the Ajax callback, in order to effectively declare your new function and have it available during the whole page lifetime.

Even if quite dummy, this code explains the idea:

<html>
<body>
<div id="div1">
</div>
<div id="div2">
<input type="button" value="Go!" onclick="go()" />
</div>
<script type="text/javascript">
var newsc = '<script id="sc1" type="text/javascript">function go() { alert("GO!") }<\/script>';
var e = document.getElementById('div1');
e.innerHTML = newsc;
eval(document.getElementById('sc1').innerHTML);
</script>
</body>
</html>

I didn't use Ajax, but the concept is the same (even if the example I chose sure isn't much smart :-)

Generally speaking, I do not question your solution design, i.e. whether it is more or less appropriate to externalize + generalize the function in a separate .js file and the like, but please take note that such a solution could raise further problems, especially if your Ajax invocations should repeat, i.e. if the context of the same function should change or in case the declared function persistence should be concerned, so maybe you should seriously consider to change your design to one of the suggested examples in this thread.

Finally, if I misunderstood your question, and you're talking about contextual invocation of the function when your Ajax callback returns, then my feeling is to suggest the Prototype approach described by krosenvold, as it is cross-browser, tested and fully functional, and this can give you a better roadmap for future implementations.

how to execute a javascript function returned from ajax response

Your response from create_chat could indicate which function will be used. For example

$.ajax({  
type: "POST",
url: "https://www.example.com/create_chat.php",
data: {
dataString: dataString
},
beforeSend: function()
{
$("#loading_indicator").show();
},
success: function(response) // response could be 1,2,3,4.. etc
{
if(response==1) {
start_chat();
}
if(response==2) {
stop_chat();
}
if(response==3) {
change_chat_room();
}
...
$(".example").html(response);

}
});

Executing a javascript function returned from AJAX response (PHP)

You have to Evaluate that code like this

eval("("+response+")");

OR

If your response contains both html and javascript code you have to do like this

 $.ajax({
url: "/snippets/js-in-ajax-response.html",
context: document.body,
success: function(responseText) {
$("#response-div").html(responseText);
$("#response-div").find("script").each(function(i) {
eval($(this).text());
});
}
});

Executing script elements inserted with .innerHTML

The OP's script doesn't work in IE 7. With help from SO, here's a script that does:

exec_body_scripts: function(body_el) {
// Finds and executes scripts in a newly added element's body.
// Needed since innerHTML does not run scripts.
//
// Argument body_el is an element in the dom.

function nodeName(elem, name) {
return elem.nodeName && elem.nodeName.toUpperCase() ===
name.toUpperCase();
};

function evalScript(elem) {
var data = (elem.text || elem.textContent || elem.innerHTML || "" ),
head = document.getElementsByTagName("head")[0] ||
document.documentElement,
script = document.createElement("script");

script.type = "text/javascript";
try {
// doesn't work on ie...
script.appendChild(document.createTextNode(data));
} catch(e) {
// IE has funky script nodes
script.text = data;
}

head.insertBefore(script, head.firstChild);
head.removeChild(script);
};

// main section of function
var scripts = [],
script,
children_nodes = body_el.childNodes,
child,
i;

for (i = 0; children_nodes[i]; i++) {
child = children_nodes[i];
if (nodeName(child, "script" ) &&
(!child.type || child.type.toLowerCase() === "text/javascript")) {
scripts.push(child);
}
}

for (i = 0; scripts[i]; i++) {
script = scripts[i];
if (script.parentNode) {script.parentNode.removeChild(script);}
evalScript(scripts[i]);
}
};

How do I return the response from an asynchronous call?

→ For a more general explanation of asynchronous behaviour with different examples, see Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

→ If you already understand the problem, skip to the possible solutions below.

The problem

The A in Ajax stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example, $.ajax returns immediately and the next statement, return result;, is executed before the function you passed as success callback was even called.

Here is an analogy which hopefully makes the difference between synchronous and asynchronous flow clearer:

Synchronous

Imagine you make a phone call to a friend and ask him to look something up for you. Although it might take a while, you wait on the phone and stare into space, until your friend gives you the answer that you needed.

The same is happening when you make a function call containing "normal" code:

function findItem() {
var item;
while(item_not_found) {
// search
}
return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

Even though findItem might take a long time to execute, any code coming after var item = findItem(); has to wait until the function returns the result.

Asynchronous

You call your friend again for the same reason. But this time you tell him that you are in a hurry and he should call you back on your mobile phone. You hang up, leave the house, and do whatever you planned to do. Once your friend calls you back, you are dealing with the information he gave to you.

That's exactly what's happening when you do an Ajax request.

findItem(function(item) {
// Do something with the item
});
doSomethingElse();

Instead of waiting for the response, the execution continues immediately and the statement after the Ajax call is executed. To get the response eventually, you provide a function to be called once the response was received, a callback (notice something? call back ?). Any statement coming after that call is executed before the callback is called.



Solution(s)

Embrace the asynchronous nature of JavaScript! While certain asynchronous operations provide synchronous counterparts (so does "Ajax"), it's generally discouraged to use them, especially in a browser context.

Why is it bad do you ask?

JavaScript runs in the UI thread of the browser and any long-running process will lock the UI, making it unresponsive. Additionally, there is an upper limit on the execution time for JavaScript and the browser will ask the user whether to continue the execution or not.

All of this results in a really bad user experience. The user won't be able to tell whether everything is working fine or not. Furthermore, the effect will be worse for users with a slow connection.

In the following we will look at three different solutions that are all building on top of each other:

  • Promises with async/await (ES2017+, available in older browsers if you use a transpiler or regenerator)
  • Callbacks (popular in node)
  • Promises with then() (ES2015+, available in older browsers if you use one of the many promise libraries)

All three are available in current browsers, and node 7+.



ES2017+: Promises with async/await

The ECMAScript version released in 2017 introduced syntax-level support for asynchronous functions. With the help of async and await, you can write asynchronous in a "synchronous style". The code is still asynchronous, but it's easier to read/understand.

async/await builds on top of promises: an async function always returns a promise. await "unwraps" a promise and either result in the value the promise was resolved with or throws an error if the promise was rejected.

Important: You can only use await inside an async function or in a JavaScript module. Top-level await is not supported outside of modules, so you might have to make an async IIFE (Immediately Invoked Function Expression) to start an async context if not using a module.

You can read more about async and await on MDN.

Here is an example that elaborates the delay function findItem() above:

// Using 'superagent' which will return a promise.
var superagent = require('superagent')

// This is isn't declared as `async` because it already returns a promise
function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}

async function getAllBooks() {
try {
// GET a list of book IDs of the current user
var bookIDs = await superagent.get('/user/books');
// wait for 3 seconds (just for the sake of this example)
await delay();
// GET information about each book
return superagent.get('/books/ids='+JSON.stringify(bookIDs));
} catch(error) {
// If any of the awaited promises was rejected, this catch block
// would catch the rejection reason
return null;
}
}

// Start an IIFE to use `await` at the top level
(async function(){
let books = await getAllBooks();
console.log(books);
})();

Current browser and node versions support async/await. You can also support older environments by transforming your code to ES5 with the help of regenerator (or tools that use regenerator, such as Babel).



Let functions accept callbacks

A callback is when function 1 is passed to function 2. Function 2 can call function 1 whenever it is ready. In the context of an asynchronous process, the callback will be called whenever the asynchronous process is done. Usually, the result is passed to the callback.

In the example of the question, you can make foo accept a callback and use it as success callback. So this

var result = foo();
// Code that depends on 'result'

becomes

foo(function(result) {
// Code that depends on 'result'
});

Here we defined the function "inline" but you can pass any function reference:

function myCallback(result) {
// Code that depends on 'result'
}

foo(myCallback);

foo itself is defined as follows:

function foo(callback) {
$.ajax({
// ...
success: callback
});
}

callback will refer to the function we pass to foo when we call it and we pass it on to success. I.e. once the Ajax request is successful, $.ajax will call callback and pass the response to the callback (which can be referred to with result, since this is how we defined the callback).

You can also process the response before passing it to the callback:

function foo(callback) {
$.ajax({
// ...
success: function(response) {
// For example, filter the response
callback(filtered_response);
}
});
}

It's easier to write code using callbacks than it may seem. After all, JavaScript in the browser is heavily event-driven (DOM events). Receiving the Ajax response is nothing else but an event.
Difficulties could arise when you have to work with third-party code, but most problems can be solved by just thinking through the application flow.



ES2015+: Promises with then()

The Promise API is a new feature of ECMAScript 6 (ES2015), but it has good browser support already. There are also many libraries which implement the standard Promises API and provide additional methods to ease the use and composition of asynchronous functions (e.g., bluebird).

Promises are containers for future values. When the promise receives the value (it is resolved) or when it is canceled (rejected), it notifies all of its "listeners" who want to access this value.

The advantage over plain callbacks is that they allow you to decouple your code and they are easier to compose.

Here is an example of using a promise:

function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}

delay()
.then(function(v) { // `delay` returns a promise
console.log(v); // Log the value once it is resolved
})
.catch(function(v) {
// Or do something else if it is rejected
// (it would not happen in this example, since `reject` is not called).
});
.as-console-wrapper { max-height: 100% !important; top: 0; }

Return statement executes before ajax response

one Way is

use async : false

Setting async to false means that the statement you are calling has to complete before the next statement in your function can be called.

$.ajax({
type:"POST",
url:"../chk.php",
data:datastring,
cache: false,
async : false,
success: function (result) {

And also why are you returning the value outside the ajax function , return the value inside ajax success if you are not using async : false

 $.ajax({
type:"POST",
url:"../chk.php",
data:datastring,
cache: false,
success: function (result) {

if(result.toString() == "success" ){

flag=true;

}

else{
$('#error').css('display', 'block');
$('#error').css('color','red');
$('#error').text(result.toString());
flag=false;
}
}

return flag;

});

javascript function response from AJAX call returning undefined

AJAX is asynchronous meaning that you cannot return a value from the callback_validation that depends on the result of the AJAX call. The reason for that is because the success callback (which is the only place where you know the value) could be executed much after the function has already returned.

So I would recommend you start using the async pattern and have your function take a callback instead of returning a value:

function callback_validation($val, $field, resultCallback) {
var $jObj=[], $data={
ci: $ci,
ui: $ui
};
$data[$field.attr('name')]=$val;
$jObj.push($data);

$.ajax({
url: $url,
type: 'post',
dataType: 'json',
success: function (res) {
resultCallback(res.valid);
},
data: $data,
error: function(xhr, desc, err) {
console.log(xhr);
console.log('Details: ' + desc + '\nError:' + err + '\n');
resultCallback(false);
},
cache: false
});
}

and now you can call your function like that:

callback_validation('value',<object>, function(result) {
console.log(result); // this will print true or false
});

It's just the asynchronous pattern of programming that you should get accustomed too if you are doing AJAX calls.

Is it possible to return javascript function via ajax from php?

Instead, consider a structured response

While what you are asking to do is possible, there are much better ways to handle this. Consider instead returning an array containing the data needed to build the links with client-side scripting. Build the Ajax to call add those links accordingly. You could expand this further to include more configurable objects, or building the html to be appended and returning that, rather than trying to run javascript eval.

function updateNav(links) {    links.forEach(function(link){        $li = $('<li></li>');        $a = $('<a></a>');        $a.prop('href',link['uri']);        $a.html(link['text']);        $li.append($a);
$('#nav').append($li); });}
var dummyData = { navLinks: [ { uri: 'http://stackoverflow.com', text: 'StackOverflow' }, { uri: 'http://google.com', text: 'Google' } ]};
var dummyHtml = { navHtml: '<ol><li><a href="http://meta.stackoverflow.com">Meta StackOverflow</a></li></ol>'};
function ajaxSimData() { var someAjaxObject = {}; someAjaxObject.success = function(data) { updateNav(data['navLinks']); };
someAjaxObject.success(dummyData);}
function ajaxSimHtml() { var someAjaxObject = {}; someAjaxObject.success = function(data) { $('#nav').after(data['navHtml']); };
someAjaxObject.success(dummyHtml);}
$('.ajaxTriggerData').click(ajaxSimData);$('.ajaxTriggerHtml').click(ajaxSimHtml);
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>
<div id="message"> Simple Examples:<br> <button class="ajaxTriggerData">Populate Nav from Data</button><br> <button class="ajaxTriggerHtml">Load HTML string after Nav</button><br></div><div id="body"> <h3>Some navigation elements: </h3> <ul id="nav"> <li><a href="#">Nav1</a></li> <li><a href="#">Nav2</a></li> <li><a href="#">Nav3</a></li> </ul></div>

function that return a value from ajax call request

You need to register a callback function, something like this:

function test() {
myFunction(function(d) {
//processing the data
console.log(d);
});
}

function myFunction(callback) {
var data;
$.ajax({
url: 'url',
data: 'data to send',
success: function (resp) {
data = resp;
callback(data);
},
error: function () {}
}); // ajax asynchronus request
//the following line wouldn't work, since the function returns immediately
//return data; // return data from the ajax request
}


Related Topics



Leave a reply



Submit