3

I'm populating a drop down with JSON data from getJSON.

Populating is working fine, but trying to establish that it's finished by comparing to data.length is not working as data.length is undefined and I can't see why!

The data looks like:

{
    "1": {
        "id": "1",
        "name": "Plymouth"
    },
    "2": {
        "id": "2",
        "name": "Torquay"
    }
}

My code looks like:

$('.locationList').empty();
$('.locationList').append('<option value="">Select...</option>');
$.getJSON('/Settings/locations.txt', function (data) {
    var dataNum = data.length;
    var counter = 1;
    $.each(data, function (i, item) {
        $('.locationList').append('<option value="' + data[i].id + '">' + data[i].name + '</option>');
        if (counter >= dataNum) {
            $('#bookTo').val(locationID + 1);
            $('#transferFrom').val(locationID);
        };
        counter++;
    });
});

This section:

if (counter >= dataNum) {
    $('#bookTo').val(locationID + 1);
    $('#transferFrom').val(locationID);
};
counter++;

Is meant to allow me to preset the values of the drop down boxes once the $.each loop has completed (this works with other lists), but it's not happening.

When I run alert(data.length) I get undefined which makes no sense as data clearly does have a length in order for it to populate the drop down box properly through the $.each, which it does!

EDIT: sorry, should add, the variable locationID is declared earlier in the script from a Cookie and IS valid

cillierscharl
  • 7,043
  • 3
  • 29
  • 47
Jamie Hartnoll
  • 7,231
  • 13
  • 58
  • 97
  • 1
    Possible duplicate of [JavaScript object literal length === undefined?](http://stackoverflow.com/questions/4690520/javascript-object-literal-length-undefined) `data` is an object, not a string or an array. Objects do not expose a `length` property. – Frédéric Hamidi Feb 24 '12 at 09:23
  • Why exactly do you need the `dataNum` variable when you have the index value of jQuery's .each() function ? – adeneo Feb 24 '12 at 09:26
  • I need the dataNum variable to determine when `$.each` has finished, because despite what it says in the docs, otherwise the value selection of the drop down box happens before it's fully populated – Jamie Hartnoll Feb 24 '12 at 10:00

4 Answers4

4

This is an object:

data = {
    "1": {
        "id": "1",
        "name": "Plymouth"
    },
    "2": {
        "id": "2",
        "name": "Torquay"
    }
}

and it doesn't have a length property.

see: only the property 1 and 2.

Are you sure you want it as an object rater then an array:

data = [
    {
        "id": "1",
        "name": "Plymouth"
    },
    {
        "id": "2",
        "name": "Torquay"
    }
]

then you have the length property and a lot of other native array methods like sort. And you can access your data like this:

data[0]

witch is equal to:

{
    "id": "1",
    "name": "Plymouth"
}
Andreas Louv
  • 46,145
  • 13
  • 104
  • 123
  • :D I've changed the source of `locations.txt` and now it works, thanks! `[{"id":"1","label":"1","name":"Plymouth"},{"id":"2","label":"2","name":"Torquay"}]` – Jamie Hartnoll Feb 24 '12 at 09:58
3

Probably not the best way of doing this, but something like this could probably be a quick fix?

$('.locationList').empty();
$('.locationList').append('<option value="">Select...</option>');
$.getJSON('/Settings/locations.txt', function (data) {
    var dataNum = 0;
    for (i in data) {if (data.hasOwnProperty(i)) {dataNum++;}}    
    var counter = 1;
    $.each(data, function (i, item) {
        $('.locationList').append('<option value="' + data[i].id + '">' + data[i].name + '</option>');
        if (counter >= dataNum) {
            $('#bookTo').val(locationID + 1);
            $('#transferFrom').val(locationID);
        };
        counter++;
    });
});
adeneo
  • 312,895
  • 29
  • 395
  • 388
2

Your JSON:

{"1":{"id":"1","name":"Plymouth"},"2":{"id":"2","name":"Torquay"}}

is an object, not an array so the length property is not defined. If you want to parse it as an array your server needs to give a response like:

{"response": [{"1":{"id":"1","name":"Plymouth"}},
{"2":{"id":"2","name":"Torquay"}}] }

with [] instead of {}

andreapier
  • 2,958
  • 2
  • 38
  • 50
  • 2
    not right! An array doesn't take the string like json: `{string: value, string: value}`. Arrays is: `[value, value]` – Andreas Louv Feb 24 '12 at 09:27
  • That can't be correct or the rest of the function would fail, surely? Ah... reading @AndreasAl answer is pointing me in the right direction along with this comment... sort of! – Jamie Hartnoll Feb 24 '12 at 09:46
0

When response.data == [], this works:

if (response.data.length === 0)

This is a Array then has length prospriety.