71

Im still somewhat of a newbie on jQuery and the ajax scene, but I have an $.ajax request performing a GET to retrieve some XML files (~6KB or less), however for the duration the user spends on that page that XML content should not / will not change (this design I cannot change, I also don't have access to change the XML file as I am reading it from somewhere else). Therefore I have a global variable that I store the response data into, and any subsequent look ups on the data are done on this variable so multiple requests don't need to be made.

Given the fact that the XML file can increase, Im not sure this is the best practice, and also coming from a java background my thoughts on global public variables are generally a no-no.

So the question I have is whether there might be a better way to do this, and a question on whether this causes any memory issues if the file expands out to some ridiculous file size?

I figure the data could be passed into a some getter/setter type functions inside the xml object, which would solve my global public variable problems, but still raises the question on whether I should store the response inside the object itself.

For example, what I currently do is:

// top of code
var xml;
// get the file
$.ajax({
  type: "GET",
  url: "test.xml",
  dataType: "xml",
  success : function(data) {
    xml = data;
  }
});
// at a later stage do something with the 'xml' object
var foo = $(xml).find('something').attr('somethingElse');
Yukulélé
  • 15,644
  • 10
  • 70
  • 94

16 Answers16

72

Here is a function that does the job quite well. I could not get the Best Answer above to work.

jQuery.extend({
    getValues: function(url) {
        var result = null;
        $.ajax({
            url: url,
            type: 'get',
            dataType: 'xml',
            async: false,
            success: function(data) {
                result = data;
            }
        });
       return result;
    }
});

Then to access it, create the variable like so:

var results = $.getValues("url string");
rfc1484
  • 9,441
  • 16
  • 72
  • 123
Charles Guilbert
  • 737
  • 1
  • 5
  • 2
  • 3
    actually just adding the 'async : false' can solve a lot of the problems you will encounter with this. – Rooster Aug 29 '12 at 16:33
  • 6
    and can create a lot of problems such as freezing a browser for several seconds :) – Armen Markossyan Feb 07 '13 at 09:18
  • async is causing alot of issues. What can solve the async problem? – Maciek Semik Apr 15 '14 at 02:10
  • BTW Can you explain this? Why can't I just declare a global variable in the Ajax success handler? – sixty4bit Oct 27 '14 at 23:38
  • 4
    This one gives warning in chrome console like `Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/.` – RN Kushwaha Aug 07 '15 at 11:46
  • came back by this, years later, by happenstance. Please DO NOT use async:false, for reasons the internet can explain better than my 500 character limit here. – Luke Schafer Mar 07 '16 at 06:23
  • @ArmenMarkossyan What would be a better alternative to this? And why would it cause a lot of problems? – Zypps987 Jul 24 '17 at 12:31
  • @Zypps987 The better alternative is to avoid such global variables and build a proper asynchronous architecture. Async programming is different from traditional ways, so it has a certain learning curve and it's impossible to explain in detail in a single comment. `async: false` makes the whole thread (tab) freeze while it finishes the call. Just try to make 10 consecutive calls in a single function an see what happens. Especially if these calls take some time (and they will always do). – Armen Markossyan Jul 25 '17 at 14:46
36

This worked for me:

var jqxhr = $.ajax({
    type: 'POST',       
    url: "processMe.php",
    data: queryParams,
    dataType: 'html',
    context: document.body,
    global: false,
    async:false,
    success: function(data) {
        return data;
    }
}).responseText;

alert(jqxhr);
// or...
return jqxhr;

Important to note: global: false, async:false and finally responseText chained to the $.ajax request.

Aakash Goplani
  • 1,150
  • 1
  • 19
  • 36
Phil Lowe
  • 361
  • 3
  • 2
  • 2
    async:false will create havoc! If you have a beforeSend with a loading gif or something, async will make it very ugly – Maciek Semik Apr 15 '14 at 01:19
  • This worked for me like a charm. I have been struggling with storing ajax response into global variable for long time dammit – King Sep 26 '16 at 12:20
35

There's no way around it except to store it. Memory paging should reduce potential issues there.

I would suggest instead of using a global variable called 'xml', do something more like this:

var dataStore = (function(){
    var xml;

    $.ajax({
      type: "GET",
      url: "test.xml",
      dataType: "xml",
      success : function(data) {
                    xml = data;
                }
    });

    return {getXml : function()
    {
        if (xml) return xml;
        // else show some error that it isn't loaded yet;
    }};
})();

then access it with:

$(dataStore.getXml()).find('something').attr('somethingElse');
Luke Schafer
  • 9,209
  • 2
  • 28
  • 29
22

You don't have to do any of this. I ran into the same problem with my project. what you do is make a function call inside the on success callback to reset the global variable. As long as you got asynchronous javascript set to false it will work correctly. Here is my code. Hope it helps.

var exists;

//function to call inside ajax callback 
function set_exists(x){
    exists = x;
}

$.ajax({
    url: "check_entity_name.php",
    type: "POST",
    async: false, // set to false so order of operations is correct
    data: {entity_name : entity},
    success: function(data){
        if(data == true){
            set_exists(true);
        }
        else{
            set_exists(false);
        }
    }
});
if(exists == true){
    return true;
}
else{
    return false;
}

Hope this helps you .

Dom
  • 1,018
  • 2
  • 11
  • 20
  • 1
    god like answer for me :D – Aditzu Dec 04 '13 at 13:34
  • 1
    This works pretty good! JUST 1 thing, if(data == true) needs to be changed. It might just be empty. – Maciek Semik Apr 13 '14 at 20:34
  • I was trying to recreate nodes from the response ajax returned. My script would work whenever I used existing nodes, but did not work when trying to recreate the objects structured from ajax response. This solution worked for me. I won't explore right now, but I suspect the async setting made the difference. – IberoMedia May 23 '14 at 22:06
  • This worked excellent for my project. All I used was the function call. Didn't need the true false stuff – user1794918 Feb 27 '17 at 11:20
10

You might find it easier storing the response values in a DOM element, as they are accessible globally:

<input type="hidden" id="your-hidden-control" value="replace-me" />

<script>
    $.getJSON( '/uri/', function( data ) {
        $('#your-hidden-control').val( data );
    } );
</script>

This has the advantage of not needing to set async to false. Clearly, whether this is appropriate depends on what you're trying to achieve.

Aidan Fitzpatrick
  • 1,950
  • 1
  • 21
  • 26
  • 2
    So simple! It worked for me, though instead of setting an input's value I used jQuery's .data() method to store JSON. – Anthony Oct 23 '17 at 20:41
  • 1
    Logical solution for some application it is really clean. Suggestion: in case of cancelled operations, it is better to reset the `value` of `your-hidden-control` – Robert Sep 12 '21 at 15:18
8

your problem might not be related to any local or global scope for that matter just the server delay between the "success" function executing and the time you are trying to take out data from your variable.

chances are you are trying to print the contents of the variable before the ajax "success" function fires.

vortex
  • 862
  • 8
  • 14
7
        function getJson(url) {
            return JSON.parse($.ajax({
                type: 'GET',
                url: url,
                dataType: 'json',
                global: false,
                async: false,
                success: function (data) {
                    return data;
                }
            }).responseText);
        }

        var myJsonObj = getJson('/api/current');

This works!!!

DarthVader
  • 52,984
  • 76
  • 209
  • 300
4

I really struggled with getting the results of jQuery ajax into my variables at the "document.ready" stage of events.

jQuery's ajax would load into my variables when a user triggered an "onchange" event of a select box after the page had already loaded, but the data would not feed the variables when the page first loaded.

I tried many, many, many different methods, but in the end, it was Charles Guilbert's method that worked best for me.

Hats off to Charles Guilbert! Using his answer, I am able to get data into my variables, even when my page first loads.

Here's an example of the working script:

    jQuery.extend
    (
        {
            getValues: function(url) 
            {
                var result = null;
                $.ajax(
                    {
                        url: url,
                        type: 'get',
                        dataType: 'html',
                        async: false,
                        cache: false,
                        success: function(data) 
                        {
                            result = data;
                        }
                    }
                );
               return result;
            }
        }
    );

    // Option List 1, when "Cats" is selected elsewhere
    optList1_Cats += $.getValues("/MyData.aspx?iListNum=1&sVal=cats");

    // Option List 1, when "Dogs" is selected elsewhere
    optList1_Dogs += $.getValues("/MyData.aspx?iListNum=1&sVal=dogs");

    // Option List 2, when "Cats" is selected elsewhere
    optList2_Cats += $.getValues("/MyData.aspx?iListNum=2&sVal=cats");

    // Option List 2, when "Dogs" is selected elsewhere
    optList2_Dogs += $.getValues("/MyData.aspx?iListNum=2&sVal=dogs");
CityPickle
  • 131
  • 1
  • 1
3
     function get(a){
            bodyContent = $.ajax({
                  url: "/rpc.php",
                  global: false,
                  type: "POST",
                  data: a,
                  dataType: "html",
                  async:false
               } 
            ).responseText;
            return bodyContent;

  }
Edmhs
  • 3,645
  • 27
  • 39
2

Ran into this too. Lots of answers, yet, only one simple correct one which I'm going to provide. The key is to make your $.ajax call..sync!

$.ajax({  
    async: false, ...
stvn
  • 1,148
  • 1
  • 8
  • 24
  • 2
    thanks for the downgrade but hey, I came here looking for a solution that didn't have a blocking operation in it's body and for other people who may stumble on this question, my solution might be the answer! – stvn Oct 10 '12 at 13:18
  • 2
    Everyone is necroposting on this question, so I might as well do it too. As of jQuery 1.8, `async: false` is deprecated, and there is always a better way to handle your code than to sync your requests. – Andrew Larsson Jan 30 '13 at 23:03
1

I know the thread is old but i thought someone else might find this useful. According to the jquey.com

var bodyContent = $.ajax({
  url: "script.php",
  global: false,
  type: "POST",
  data: "name=value",
  dataType: "html",
  async:false,
  success: function(msg){
     alert(msg);
  }
}).responseText;

would help to get the result to a string directly. Note the .responseText; part.

Aakash Goplani
  • 1,150
  • 1
  • 19
  • 36
user759740
  • 127
  • 3
  • 16
0

Similar to previous answer:

<script type="text/javascript">

    var wait = false;

    $(function(){
        console.log('Loaded...');
        loadPost(5);
    });

    $(window).scroll(function(){
      if($(window).scrollTop() >= $(document).height() - $(window).height()-100){
        // Get last item
        var last = $('.post_id:last-of-type').val();
        loadPost(1,last);
      }
    });

    function loadPost(qty,offset){
      if(wait !== true){

        wait = true;

        var data = {
          items:qty,
          oset:offset
        }

        $.ajax({
            url:"api.php",
            type:"POST",
            dataType:"json",
            data:data,
            success:function(data){
              //var d = JSON.parse(data);
              console.log(data);
              $.each(data.content, function(index, value){
                $('#content').append('<input class="post_id" type="hidden" value="'+value.id+'">')
                $('#content').append('<h2>'+value.id+'</h2>');
                $('#content').append(value.content+'<hr>');
                $('#content').append('<h3>'+value.date+'</h3>');
              });
              wait = false;
            }
        });
      }
    }
</script>
Kyle Coots
  • 2,041
  • 1
  • 18
  • 24
0

Just use this. simple and effective:

var y;

function something(x){
return x;
}

$.get(bunch of codes, function (data){

y=something(data);
)}

//anywhere else
console.log(y);
RezaAhmadi
  • 17
  • 5
0

IMO you can store this data in global variable. But it will be better to use some more unique name or use namespace:

MyCompany = {};

...
MyCompany.cachedData = data;

And also it's better to use json for these purposes, data in json format is usually much smaller than the same data in xml format.

zihotki
  • 5,201
  • 22
  • 26
  • When you are using a lot of global vars this is bad, but when you use them carefully this helps a lot. JQuery uses global vars ( $ and jQuery at least), ExtJS uses global vars too. – zihotki Jun 01 '09 at 15:54
0

I'd suggest that fetching large XML files from the server should be avoided: the variable "xml" should used like a cache, and not as the data store itself.

In most scenarios, it is possible to examine the cache and see if you need to make a request to the server to get the data that you want. This will make your app lighter and faster.

cheers, jrh.

jrharshath
  • 25,975
  • 33
  • 97
  • 127
0

.get responses are cached by default. Therefore you really need to do nothing to get the desired results.

redsquare
  • 78,161
  • 20
  • 151
  • 159