0

I want to use AJAX to get a list of Styles from my database. The Styles have a Category FK that I want to use to sort the Styles into a JSON object and then use that JSON with JavaScript to populate a Select list based on the Category chosen by the user.

Here is my code:

$(document).ready(function () {

    var styles = {
        "cat1": [],
        "cat2": [],
        "cat3": [],
        "cat4": []
    }

    $.getJSON("/Inventory/GetStyles", function (data) {
        $(data).each(function (i, d) {
            var n = {
                "StyleID": d.StyleID,
                "Name": d.Name,
                "CategoryID": d.CategoryID
            };

            switch (d.CategoryID) {
                case 1:
                    styles.cat1.push(n);
                    break;
                case 2:
                    styles.cat2.push(n);
                    break;
                case 3:
                    styles.cat3.push(n);
                    break;
                case 4:
                    styles.cat4.push(n);
                    break;
            };
        });
    });

    alert(styles.cat1[0].Name);
});

When I use debugger; and step through, I see that everything seems to be working just fine. styles is filled with data as expected but the alert never goes off. Instead, I get an error:

TypeError: styles.cat1[0] is undefined

This is confusing because, when debugging, I can mouse over and see that styles.cat1[0].Name has the value it should. Oddly, however, this only works when I put the debugger; statement inside my AJAX call, as seen here:

example a

If I move the debugger; statement to outside the AJAX call, the styles.cat1[0].Name changes to undefined, as seen here:

example b

I am at a loss as to how to get this straight. Any help is greatly appreciated.

Jason
  • 591
  • 2
  • 10
  • 23
  • 1
    There are no arrays in JSON, it's a format for strings and you probably have javascript objects ? – adeneo Nov 21 '13 at 16:28
  • 5
    Ajax is async. The alert happens before the ajax call finishes. – Jason P Nov 21 '13 at 16:29
  • Can I suggest `styles['cat'+d.CategoryID].push(n)` rather than that switch statement? – George Nov 21 '13 at 16:33
  • 1
    possible duplicate of [How to return the response from an AJAX call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – Blazemonger Nov 21 '13 at 16:37
  • Yeah, I'm new to AJAX so, though I am aware of its asynchronous nature, I was totally not even thinking about it. I was thinking I was manipulating the data incorrectly or something (hence the way I worded the question). I facepalmed so, ya.. Thanks for quick replies! :) – Jason Nov 21 '13 at 16:47

2 Answers2

1

you are trying to access styles.cat1[0] before the ajax call has been finished. move the alert line up into callback function

$.getJSON("/Inventory/GetStyles", function (data) {
        $(data).each(function (i, d) {
            var n = {
                "StyleID": d.StyleID,
                "Name": d.Name,
                "CategoryID": d.CategoryID
            };

            switch (d.CategoryID) {
                case 1:
                    styles.cat1.push(n);
                    break;
                case 2:
                    styles.cat2.push(n);
                    break;
                case 3:
                    styles.cat3.push(n);
                    break;
                case 4:
                    styles.cat4.push(n);
                    break;
            };
        });
        alert(styles.cat1[0].Name);
    });
Alex
  • 9,911
  • 5
  • 33
  • 52
1

As others have pointed out, your alert() happens before the Ajax request even returns.

This means alert() must be part of the success callback function. To make this easier you really should get into using jQuery's deferred callback paradigm.

It's a lot more straightforward than cramming everything into a single callback function. Compare:

$(function () {
    $.getJSON("/Inventory/GetStyles")
    .then(function (data) {
        var styles = {};
        $.each(data, function (i, d) {
            var catN = "cat" + d.CategoryID;

            if (!(catN in styles)) {
                styles[catN] = [];
            }

            styles[catN].push({
                StyleID: d.StyleID,
                Name: d.Name,
                CategoryID: d.CategoryID
            });
        });
        return styles;
    })
    .done(function (styles) {
        alert(styles.cat1[0].Name);
    });
});

Recommended reading http://api.jquery.com/category/deferred-object/

Tomalak
  • 332,285
  • 67
  • 532
  • 628