0

I have scoured the other question/answer for this and implemented everything and I still cannot access the values of the object. Here's the code I am using:

function apply_voucher(voucher) {
    var dates = $.parseJSON($("[name='dates']").val());
    var voucher_yes_no = new Array();
    var voucher_reduction = new Array();

    if(voucher.length > 0)
    {
        $.each(dates, function(room_id, these_dates) {
            $.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
                if(result.result == 'ok') {
                    voucher_yes_no.push('yes');
                    voucher_reduction.push(result.voucher_reduction);
                } else {
                    voucher_yes_no.push('no');
                }
            }, 'json');
        });

        // check if there are any yes's in the array
        if('yes' in voucher_yes_no) {
            console.log("no yes's");
        } else {
            console.log(voucher_reduction);
            console.log(typeof voucher_reduction);
            for (var prop in voucher_reduction) {
                console.log(prop);
                console.log(voucher_reduction[prop]);
                if (voucher_reduction.hasOwnProperty(prop)) { 
                    console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
                }
            }
        }
    }
}

Apologies for the constant console logging - I'm just trying to track everything to make sure it's all doing what it should. The console output I get from this is below:

screenshot

...which shows the object containing one value, "1.01" and my console.log of the typeof it to make sure it is actually an object (as I thought I was going mad at one point). After this there is nothing from inside the for-in loop. I have tried jquery's $.each() also to no avail. I can't understand why nothing I'm trying is working!

mdml
  • 22,442
  • 8
  • 58
  • 66
Helen Danger Burns
  • 421
  • 2
  • 9
  • 28
  • can you share the value in `voucher_reduction`? – Arun P Johny Nov 20 '13 at 13:15
  • 1
    Did you not get any error message? – Qantas 94 Heavy Nov 20 '13 at 13:16
  • Apologies for typo. I have changed it in my code (and updated the code above) and there is still absolutely nothing in the console. No errors or anything! – Helen Danger Burns Nov 20 '13 at 13:18
  • @ArunPJohny - I have, it is in the screenshot in the original post – Helen Danger Burns Nov 20 '13 at 13:20
  • 2
    Isn't it an Array [], instead of an object? – Marvin Smit Nov 20 '13 at 13:20
  • What do you get if you log voucher_reduction[0] ? – user1021726 Nov 20 '13 at 13:21
  • @MarvinSmit - I have tried treating it as an array as well, just in case, using `var i = 0; i < voucher_reduction.length; i++` but it still shows nothing. logging voucher_reduction.length returns 0 – Helen Danger Burns Nov 20 '13 at 13:22
  • @ArunPJohny ???! It's there in the screenshot - object – Helen Danger Burns Nov 20 '13 at 13:23
  • Where do you instantiate voucher_reduction? – user1021726 Nov 20 '13 at 13:24
  • Earlier in the code with `var voucher_reduction = new Array();` which I know means it should be an array, but after this I 'push' values onto it dynamically from the json results of a post and when I logged it out afterwards it seems to be an object. Either way I've tried solutions for both and nothing seems to work! – Helen Danger Burns Nov 20 '13 at 13:26
  • seems to be fine http://jsfiddle.net/arunpjohny/nXkWg/1/ – Arun P Johny Nov 20 '13 at 13:27
  • Could you edit your post where you show us how you instantiate and push to the array? – user1021726 Nov 20 '13 at 13:28
  • voucher_reduction seems to be 'voucher_reduction = Array(0)' i'm also confused where the '0 "1.01"' comes from – Marvin Smit Nov 20 '13 at 13:29
  • @user1021726 - yes, doing this now as I think it must be the problem – Helen Danger Burns Nov 20 '13 at 13:31
  • @ArunPJohny - your example does work great, but that is assuming the voucher_reduction is an array, which it isn't... I'm editing the question now to show initiation of it. – Helen Danger Burns Nov 20 '13 at 13:31
  • This is the classic treating an Asynchronous call as Synchronous problem that is asked 20 times a day. – epascarello Nov 20 '13 at 13:49
  • I still don't think it's quite that straight forward... I'm not totally unschooled on this. The loop doesn't run unless it finds at least one 'yes' in the voucher_yes_no array, and this is pushed at the same times as the '1.01' (which is result.voucher_reduction) is, so if there is a yes, then there is at least one entry in the voucher_reduction object. Please don't just put it down to async vs. sync unless it actually is. – Helen Danger Burns Nov 20 '13 at 13:57
  • Add `console.log("Pushing");` statement before the push line. Add `console.log("Running if")` before the if check after the each. What do you see in the log? – epascarello Nov 20 '13 at 14:20
  • You're right. It is all backwards. I have also tried the when then but it is still backwards so I can't be doing it right. I've asigned the whole each() to a var: `var get_voucher_results = $.each(dates, fu...` and then put that in the when: `$.when(get_voucher_results)...`. I know this is a different issue now but what am I doing wrong there.. all the docs show ajax as files '`$.ajax( "test.aspx" )`' and a google search on 'jquery when with post' isn't terribly helpful! – Helen Danger Burns Nov 20 '13 at 14:32
  • From your last update : `if('yes' in voucher_yes_no) {` can't work. It check if 'yes' is a key of voucher_yes_no, but it's an array. Use `voucher_yes_no.indexOf('yes')`. It returns -1 if is not find. – Techniv Nov 20 '13 at 16:30
  • By the time the ajax call has pushed values to it, it is an object. I don't know why but I tried what you suggested first off and it simply didn't work. Treating it as an object did and does. I know it shouldn't but it does... I don't know what about pushing to the array from json makes it an object but it does! – Helen Danger Burns Nov 20 '13 at 17:07

5 Answers5

1

It does not work because the Ajax call is asynchronous!

You are reading the values BEFORE it is populated!

Move the code in and watch it magically start working since it will run after you actually populate the Array!

function apply_voucher(voucher) {
    var room_id = "169";
    var dates = $.parseJSON($("[name='dates']").val());
    var voucher_reduction = new Array();

    $.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
        if(result.result == 'ok') {
            voucher_reduction.push(result.voucher_reduction);
        }

        console.log(voucher_reduction);
        console.log(typeof voucher_reduction);
        for (var prop in voucher_reduction) {
                console.log(prop);
                console.log(voucher_reduction[prop]);
                if (voucher_reduction.hasOwnProperty(prop)) { 
                    console.log("prop: " + prop + " value: " + voucher_reduction[prop]);
                }
        }




    }, 'json');


}

From what it looks like, you plan on making that Ajax call in a loop. For this you need to wait for all of the requests to be done. You need to use when() and then(). It is answered in another question: https://stackoverflow.com/a/9865124/14104

Community
  • 1
  • 1
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • But the correct returned values are right there, logged, before I attempt the loop?! – Helen Danger Burns Nov 20 '13 at 13:40
  • Because of a bug http://stackoverflow.com/questions/8249136/why-does-javascript-object-show-different-values-in-console-in-chrome-firefox – epascarello Nov 20 '13 at 13:43
  • ...and I appreciate what you're saying about moving it into the post but I can't do this as the post is within an each loop. I didn't think it was relevant but I'll update the code again to show it all. – Helen Danger Burns Nov 20 '13 at 13:47
  • Guess what, you have no choice! You need to put the logic into the callback. Pass in a function that has the code you need to execute. That is how asynchronous calls work! If you need to do it with loops, you need to look at promises. – epascarello Nov 20 '13 at 13:48
  • Hi, I've put the full code in now... and I have looked at promises but I was under the impression that promise() and done() etc. were only to be used with animations etc.? – Helen Danger Burns Nov 20 '13 at 13:53
  • 1
    I mean `when()` and `then()`, coffee has not kicked in yet. http://api.jquery.com/jQuery.when/, – epascarello Nov 20 '13 at 13:55
  • Oooo, now I've not come across that before. Awesome. Maybe that's the way forward with this then, although I think my last comment on the original post still stands. – Helen Danger Burns Nov 20 '13 at 13:58
1

Just to say for future viewers that changing the way I did this to use proper deferred objects and promises, which blew my head up for a while, but I got there! Thanks for all the help, particularly @epascarello for pointing me in the right direction :) As soon as I started doing it this way the arrays began behaving like arrays again as well, hooray!

Here's the final code:

function apply_voucher(voucher) {
    var booking_id = $("[name='booking_id']").val();
    var dates = $.parseJSON($("[name='dates']").val());

    if(voucher.length > 0) {
        var data = []; // the ids coming back from serviceA
        var deferredA = blah(data, voucher, dates); // has to add the ids to data
        deferredA.done(function() { // if blah successful...
            var voucher_yes_no = data[0];
            var voucher_reduction = data[1];

            if(voucher_yes_no.indexOf("yes") !== -1)
            {
                console.log("at least one yes!");
                // change value of voucher_reduction field
                var reduction_total = 0;
                for(var i = 0; i < voucher_reduction.length; i++) {
                    reduction_total += voucher_reduction[i];
                }
                console.log(reduction_total);
            }
            else
            {
                console.log("there are no yes's");
            }
        });
    }
}

function blah(data, voucher, dates) {
    var dfd = $.Deferred();
    var voucher_yes_no = new Array();
    var voucher_reduction = new Array();
    var cycles = 0;
    var dates_length = 0;
    for(var prop in dates) {
        ++dates_length;
    }
    $.each(dates, function(room_id, these_dates) {
        $.post('/multiroom/check_voucher/'+voucher+'/'+room_id, function(result) {
            if(result.result == 'ok') {
                voucher_reduction.push(result.voucher_reduction);
                voucher_yes_no.push('yes');
            } else {
                voucher_yes_no.push('no');
            }
            ++cycles;
            if(cycles == dates_length) {
                data.push(voucher_yes_no);
                data.push(voucher_reduction);
                dfd.resolve();
            }
        }, 'json');
    });
    return dfd.promise();
}
Helen Danger Burns
  • 421
  • 2
  • 9
  • 28
0

in this line:

console.log(vouncher_reduction[prop]);
               ^

The name of the variable is wrong (then) and probably that is breaking your code.

Adminiculo
  • 303
  • 1
  • 14
0

Can you show how voucher_reduction is defined? I am wondering where the second line of the debug output comes from, the one starting with '0'.

FrankZ
  • 121
  • 1
  • 5
0

I think there are no problem with your loop. But perhaps with your object.

Are you sure what properties has enumerable ? Try to execute this to check :

Object.getOwnPropertyDescriptor(voucher_reduction,'0');

If it return undefined, the property was not exist.

Techniv
  • 1,967
  • 15
  • 22