'Getting Stored JSON data after Ajax is Complete

I am currently doing an exercise on Jquery, Ajax and JSON. I have found a few ways to get data, but now I would like to store this data from JSON into a variable. To my knowledge, JSON is just one big fat array of objects.

My JSON File looks like this:

{
    "Products" : [{
            "Id": 11,
            "Name": "Keyboard",
            "Description": "Microsoft Keyboard",
            "PriceExVat": 199.95,
            "QtyInStock": 11
        },
        {
            "Id": 211,
            "Name": "Mouse",
            "Description": "Microsoft 3 button Mouse with scroller",
            "PriceExVat": 199.95,
            "QtyInStock": 30
        },
        {
            "Id": 35,
            "Name": "TowerCase",
            "Description": "Mini Tower Case with 450W power unit",
            "PriceExVat": 600.95,
            "QtyInStock": 23
        },
        {
            "Id": 58,
            "Name": "Monitor",
            "Description": "17inch LCD monitor",
            "PriceExVat": 1499.95,
            "QtyInStock": 12
        }]
}

And my Jquery Code looks like this:

        var products;           
        $(document).ready(function(){       
            $.ajax({
                type: 'GET',
                url: 'data/Products.json',
                data: { get_param: 'value'},
                dataType: 'json',
                complete: function(data){
                    products = data; //Store JSON data
                }
            });
        });

        $(document).ajaxComplete(function(){
            alert(products); //returns object [Object]. When attempting to get data here like products[0].Name, an error occurs saying that Name does not exist
        });

The reason why I have done my code like this is because I know that ajax is Asynchronous javascript and xml. So If I were to use success : function(){...}, there would be no guarentee that my data would be saved to the variable products (i.e a timing issue).

So I set the code for ajax to store the data when the operation is complete. this will fire the ajaxComplete() event, theoretically allowing me to access my data I saved to the variable.

There is a hiccup here though, and the reason to my question. If I alert(products), I get the response

Returned Data 1

Altering my code a little (because now I think there should be something stored in that variable), to alert(products.Products[0].Name); , an error is thrown (implying that this variable my be undefined)

Response Error

Is there any advice anyone can pass along to me to follow for me to get the data? The goal of this variable is that I would like to use it for pagination into my table, and also lessen the amount of calls to the json file (which may become a remote hosted file later), by rather using data stored in a variable.

Edit Changed alert to console.Log

Object {readyState: 4, setRequestHeader: function, getAllResponseHeaders: function, getResponseHeader: function, overrideMimeType: function…}

Not what I was hoping to see.

Edit Apparently I failed to even show the log properly.

Object {readyState: 4, setRequestHeader: function, getAllResponseHeaders: function, getResponseHeader: function, overrideMimeType: function…}
abort: function (a){a=a||"abort",p&&p.abort(a),w(0,a);return this}
always: function (){i.done.apply(i,arguments).fail.apply(i,arguments);return this}
complete: function (){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this}
done: function (){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this}
error: function (){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this}
fail: function (){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this}
getAllResponseHeaders: function (){return s===2?n:null}
getResponseHeader: function (a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c}
isRejected: function (){return!!i}
isResolved: function (){return!!i}
overrideMimeType: function (a){s||(d.mimeType=a);return this}
pipe: function (a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()}
progress: function (){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this}
promise: function (a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}
readyState: 4
responseText: "{
↵   "Products" : [{
↵           "Id": 11,
↵           "Name": "Keyboard",
↵           "Description": "Microsoft Keyboard",
↵           "PriceExVat": 199.95,
↵           "QtyInStock": 11
↵       },
↵       {
↵           "Id": 211,
↵           "Name": "Mouse",
↵           "Description": "Microsoft 3 button Mouse with scroller",
↵           "PriceExVat": 199.95,
↵           "QtyInStock": 30
↵       },
↵       {
↵           "Id": 35,
↵           "Name": "TowerCase",
↵           "Description": "Mini Tower Case with 450W power unit",
↵           "PriceExVat": 600.95,
↵           "QtyInStock": 23
↵       },
↵       {
↵           "Id": 58,
↵           "Name": "Monitor",
↵           "Description": "17inch LCD monitor",
↵           "PriceExVat": 1499.95,
↵           "QtyInStock": 12
↵       },
↵       {
↵           "Id": 234,
↵           "Name": "Laptop",
↵           "Description": "Acer Core I5 Laptop",
↵           "PriceExVat": 6999.95,
↵           "QtyInStock": 7
↵       },
↵       {
↵           "Id": 789,
↵           "Name": "CarryCase",
↵           "Description": "Targus Carry Case",
↵           "PriceExVat": 399.95,
↵           "QtyInStock": 20
↵       },
↵       {
↵           "Id": 7,
↵           "Name": "Harddrive",
↵           "Description": "1TB External Hard Drive",
↵           "PriceExVat": 999.95,
↵           "QtyInStock": 100
↵       },
↵       {
↵           "Id": 51,
↵           "Name": "Projector",
↵           "Description": "HD Projector",
↵           "PriceExVat": 4995.95,
↵           "QtyInStock": 1
↵       },
↵       {
↵           "Id": 901,
↵           "Name": "Joystick",
↵           "Description": "Microsoft Joystick",
↵           "PriceExVat": 400.95,
↵           "QtyInStock": 2
↵       },
↵       {
↵           "Id": 500,
↵           "Name": "USBCable",
↵           "Description": "3m USB-toUSB cable",
↵           "PriceExVat": 80.95,
↵           "QtyInStock": 5
↵       }]
↵}"
setRequestHeader: function (a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this}
state: function (){return e}
status: 200
statusCode: function (a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this}
statusText: "OK"
success: function (){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this}
then: function (a,b,c){i.done(a).fail(b).progress(c);return this}
__proto__: Object


Solution 1:[1]

So I tinkered around and found the parseJSON method. From the data I saw in the Ajax Response, I figured I could take the Ajax ResponseText (Which was the data I needed), store it in the variable, and parse it to JSON.

Lo an Behold the working product:

        var products;           
        $(document).ready(function(){       
            $.ajax({
                type: 'GET',
                url: 'data/Products.json',
                data: { get_param: 'value'},
                dataType: 'json',
                complete: function(data){
                    products = data;
                }
            });
        });

        $(document).ajaxComplete(function(){            
            products = $.parseJSON(products.responseText); //Takes AJAX Reponse Text and parses it to JSON
            console.log(products.Products[0].Name);
        });

Solution 2:[2]

Your complete function has an argument of data, but realistically it’s a jQuery XHR object. If your server is setting the content type to application/json, you should be able to just use products = data.responseJSON. Also, I’d change that variable name from data to something more like xhr.

https://api.jquery.com/jQuery.ajax/

See the section about the complete method as well as the JSON part of the Data Types section.

If I were you, I’d write it all like this:

$(document).ready(function(){       
  $.getJSON('data/Products.json?get_param=value').
    done(function(data){
      console.log(data.Products[0].name);
    });
});

A few things to note with this:

  1. Get rid of the global products variable. This code runs asynchronously and so you won’t know when it’s safe to use the variable. It’s best to just perform your actions using the Promise syntax (the done method), since that code runs once the Ajax response is received, and your data actually exists.
  2. Only use ajaxComplete for global code. It’s not meant for one-off Ajax calls, since it runs for every Ajax call every time. It’s meant for global handling like showing a message if an error occurs, or a login form if the server responds in a way that means you need to sign in.
  3. Ajax’s complete callback returns a Jquery XHR object, so you’ll need to use the responseJSON property on it if you want parsed json.
  4. Use the Promise syntax (the done method) as opposed to callbacks, since it’s a bit cleaner looking, and organization always helps prevent bugs, and is more extensible if you plan to write generic methods and reuse code (returning the Ajax call and calling methods off of it is much cleaner than passing in a lot of callback functions as options). Additionally, the fist argument is actually data here, so you don’t need to call the responseJSON property.
  5. Ditch unnecessary options in your Ajax call. GET is the default method, so specifying it is unnecessary. Data Type is automatic, so if your server is sending the correct Content-Type header as it should be, jquery will just know that the response is json.
  6. Stick to shortcut methods if you can. By using getJSON, you’ve take a handful of the properties that were previously manually specified and still explicitly specify them, but in a shorthand way. getJSON still calls ajax.
  7. Avoid using a JSON body for GET requests. It’s not very common, and it’s often preferred to just include the parameters in the URL, since GET requests are what browsers do when you visit one through the address bar. A body is usually only used for POST or PUT/PATCH.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Nate