0

i'm trying to get data from a callback, and puts this data in a global variable, like this.

var x;
  CartolaRutAccountAJAXFacade.getCargarValores(dwr.util.byId('combo').value, function(data){
    x = data;
  });

console.log(x);

In console log i'm getting undefined. If i execute x after few seconds, i get the right data.

What i do i have to do? Thank's guys.

PD: I'm doing this from capybara execute_script for scraping reasons, so i need return x for get the data with evaluate_script.

fabian818
  • 97
  • 1
  • 7
  • Duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Michael Geary Jun 03 '17 at 05:26

3 Answers3

0

Michael makes a good point on why your implementation isn't working. Since you are making an asynchronous call, the order in which the javascript is executed is:

  1. Create Variable x
  2. Send Ajax call
  3. Execute console.log(x)
  4. Assign data to x (when then data is returned back)

The script will not wait for the data to return before executing the next line, as a result when the next line is called x has not been assigned to data.


If you need to handle the data in some way, you should create a function and call that function within the callback:

var x;

function handleData() {
    console.log(x);
}

CartolaRutAccountAJAXFacade.getCargarValores(dwr.util.byId('combo').value, function(data){
    x = data;
    handleData();
});

Alternatively, you could pass the data into the function via a parameter if you need, instead of assigning it to x or using an anonymous function.

function handleData(data) {
    console.log(data);
}

CartolaRutAccountAJAXFacade.getCargarValores(dwr.util.byId('combo').value, handleData(data));

Answer to Comments below

You won't be able to return x on the first on your first execution because it needs time for the Ajax call to return back data. If you are simply trying to return the data from within the entire function it may be easier to simplify everything to this:

useLoadingMessage();
dwr.engine.beginBatch();

CartolaRutAccountAJAXFacade.getCargarValores(dwr.util.byId('combo').value, function(data){

    console.log(data);

    // You may also want to do this, if you are looking 
    // to return the data from within evaluate_script:
    //
    // return data; 

});

dwr.engine.endBatch();
Jason Lemrond
  • 407
  • 2
  • 7
  • It doesn't work for me, really what i want is return that value in first executed. Here is the code and the result. https://pasteboard.co/dTiL4llQ3.png – fabian818 Jun 03 '17 at 00:44
  • Sorry, didn't see this until now. What do you need the data to do? In your code you've assigned data to x, now you do something with that data (x). Putting `x` in your function won't do anything since it's simply a variable. You'll most likely need to perform some function on x. – Jason Lemrond Jun 03 '17 at 04:42
  • I added some info to the answer above. In the image you posted it looks like you are calling handleData() twice. That may be why you are seeing undefined. If it is looking for only one set of data, then when you return x the first time through it will be undefined. The trick to async (ajax) calls is to wait until data is returned back before you begin processing it. – Jason Lemrond Jun 03 '17 at 05:19
0

You're making an async call, so the console.log() is occurring before the AJAX call is returning. Jason's example will work for you.

0

As mentioned in the other answers, the real issue here is that you're making an async call and have no way of knowing (from Capybara) when that call has finished. Depending on what driver you're using for Capybara there are a couple of potential solutions.

For all JS capable drivers you should be able to store the value in a variable in window, and then retrieve in a loop until non nil

session.execute_script("CartolaRutAccountAJAXFacade.getCargarValores(dwr.util.byId('combo').value, function(data){
window.my_value = data;})")

begin
  sleep 0.05;
  my_val = session.evaluate_script("window.my_value")
end while my_val.nil?

which should fire off your initial script and then keep retrying until a value has been returned. Note, this is naively assuming a non empty value will be returned, you may need timeouts/better value checking depending exactly on the data being returned.

If using the selenium driver with Firefox or Chrome you can clean this up a bit by using seleniums execute_async_script which will handle all the waiting for you and not return until a callback (passed into the script as the last parameter - in this case there are no other parameters passed so the callback script is arguments[0]) is called.

session.driver.browser.execute_async_script("CartolaRutAccountAJAXFacade.getCargarValores(dwr.util.byId('combo').value, arguments[0])")
Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78