1

I've been messing around with an Ajax upload tutorial I found here. I'm trying to check if the server returned "error" as the status. I found it out, it's data.result. When I do console.log(data) when data is defined, result is {"status":"error"} as expected, but when I try to call data.result in the same function, it returns undefined. I tried everything, defining it in a global variable when it's not undefined, and even passing it to another function. Here's what I have:

    progress: function(e, data){
        // calc the completion percentage of the upload
        var progress = parseInt(data.loaded / data.total * 100, 10);
        console.log(data);
        /* console log:
            Object {disabled: false, create: null, dropZone: b.fn.b.init[1], pasteZone: b.fn.b.init[1], replaceFileInput: true…}
            (more values)
            result: "{"status":"error"}"
            (more values)
        */
        // update hidden input field and trigger a change
        data.context.find('input').val(progress).change();

        if(progress == 100){
            updateProgress(data);
        }
    },

// ... later on in the file ...

function updateProgress(data){
    console.log(data);
    if(JSON.parse(data.result).status === 'error'){
        data.context.addClass('error');
    }else{
        data.context.removeClass('working');
        $('#drop').fadeOut(function(){
            $('#drop').remove();
            if(debug === 0){window.location = 'http://datastorage.iquestria.net/images/'+data.files[0].name+'?v2';}
        });
    }
}
tjhorner
  • 351
  • 2
  • 16

2 Answers2

0

After much discourse, the eventual problem was that data.result is only available reliably in the done callback, not in the progress callback where the OP was trying to access it.


The result of your Ajax call can ONLY be used in the callback where the data is provided. You cannot use it anywhere else. This is because the callback is called asynchronously and finishes sometime LATER after the rest of your function has already finished.

See this answer for more detail: How do I return the response from an asynchronous call?


Also, if you're using jQuery's ajax calls properly, you shouldn't have to do any JSON parsing yourself as jQuery will do all that for you. I don't quite understand exactly what the result is that you're getting, but if you specify the right type of data result to the ajax call, jQuery will parse it for you automatically and you won't have to call JSON.parse() yourself.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Yes, but what if I get the result when it's returned, say in `ajaxResult`. Can't I use it after that? – tjhorner Mar 23 '14 at 03:19
  • AJAX and `return` don't mix, that's the point, you have to work with callbacks or promises. – elclanrs Mar 23 '14 at 03:20
  • Well, not `return`ed, just... given, I guess. For example, if I declare `ajaxResult` at the beginning of the file, and if I do `ajaxResult = data;`, it will be global, correct? – tjhorner Mar 23 '14 at 03:22
  • Yes, but it won't work. Assignment and AJAX don't play well either. An asynchronous callback is basically a continuation that will happen at some point in the future, the assignment will occur only when the callback runs, thus you'll get `undefined` when trying to use a variable that isn't assigned yet. See the question linked in this answer, that explains everything you need to know. – elclanrs Mar 23 '14 at 03:24
  • @GeekyGamer14 - you can put the data in a global variable and use it later - the problem is that the code that's trying to use it later won't know when it's available. The "A" in Ajax stands for asynchronous which means that it returns some unknown time later. The ONLY reliable way to use the data returned from any asynchronous callback is to either use the data in the callback or call some other function and pass it the data. This is how asynchronous programming works and you just need to adapt your programming style to work that way. Trying to pretend it's not asynchronous will not work. – jfriend00 Mar 23 '14 at 03:25
  • @jfriend00 Yes, I understand that is what Ajax is. My `progress` function is the Ajax callback, where it receives the `data` variable. It's weird because when I do `console.log(data)` within that function, it is populated, but when I try to call one of the variables within it, it's undefined. – tjhorner Mar 23 '14 at 03:28
  • @GeekyGamer14 - OK, let's confine our discussion then to ONLY the operations you try in the function where the data is first returned fromt he ajax call. What EXACT code are you trying that returns `undefined` on the returned `data` in the progress function? And, what exactly is in the `data` variable? We're flying blind here without knowing exactly what the data is or exactly what you're trying to do. – jfriend00 Mar 23 '14 at 03:40
  • @GeekyGamer14 - perhaps you should do a `console.log(data)`, expand it all in the debugger and then paste into your question exactly what is there. Then, tell us exactly what code you're trying to execute on that data structure. – jfriend00 Mar 23 '14 at 03:44
  • @GeekyGamer14 - and which line of code fails with exactly what error message? – jfriend00 Mar 23 '14 at 03:48
  • If you want the exact website where I'm getting this, it's here: http://images.iquestria.net/shitloader/ – tjhorner Mar 23 '14 at 03:50
  • I get `Uncaught SyntaxError: Unexpected token u script.js:114` (which means the JSON.parse is trying to parse `undefined` – tjhorner Mar 23 '14 at 03:51
  • @GeekyGamer14 - So, are you saying that this error occurs on the `JSON.parse()` line of code in `updateProgress()`? If so, then `data.result` is not what you think it is. I'd suggest that you do a console.log on it right before you call `JSON.parse()`. FYI, the actual page URL is more useful if you tell us what steps to follow to reproduce the problem. – jfriend00 Mar 23 '14 at 03:56
  • @jfriend00 I said in the question, "when I try to call data.result in the same function, it returns `undefined`". When I try to get `data.result` from JSON.parse, it's undefined for some reason, which is odd because earlier in the function it had a value. – tjhorner Mar 23 '14 at 03:59
  • OK, when I set a breakpoint in the debugger at the beginning of `updateProgress()` and then drop a file into your page, the `data` variable that comes in the first time has no `result` property at all. – jfriend00 Mar 23 '14 at 04:01
  • Weird, when I upload a file with `console.log(data)` at the beginning, it turns out like this: http://i.gyazo.com/9d2479271a212556b05fbb18e2b6e5d1.gif – tjhorner Mar 23 '14 at 04:07
  • @GeekyGamer14 - sorry, but the animated GIF plays too fast for me to follow what it's trying to show. – jfriend00 Mar 23 '14 at 04:09
  • Here's the MP4, you can slow it down: http://i.gyazo.com/9d2479271a212556b05fbb18e2b6e5d1.mp4 – tjhorner Mar 23 '14 at 04:11
  • @GeekyGamer14 - Is it possible that data.result is supposed to be there on the `done` callback, not the progress callback? The examples I see access data.result in the `done` handler. – jfriend00 Mar 23 '14 at 04:12
  • @GeekyGamer14 - I don't see `data.result` in that movie. Am I missing something? – jfriend00 Mar 23 '14 at 04:14
  • Here, let me try that. Wow, it worked. Thanks a bunch! I should have figured that out, now I feel stupid. – tjhorner Mar 23 '14 at 04:17
  • @GeekyGamer14 - OK, I will add that to my answer. – jfriend00 Mar 23 '14 at 04:18
0

Looking at your code it looks like

JSON.parse(data.result).status

should be

JSON.parse(data).result.status

if 'result' is part of your JSON response. Like if your JSON is result: {"status":"error"} result won't be available until you're parse your data.

Class
  • 3,149
  • 3
  • 22
  • 31
  • `data` has things such as the request URI and the server `result`. So no, this won't work. – tjhorner Mar 23 '14 at 03:45
  • I don't think this is right. It's `data.result` that is the JSON string so `JSON.parse(data.result).status` looks right to me. the `data` object has this item in it: `result: '{"status":"error"}'`. – jfriend00 Mar 23 '14 at 03:52
  • I think it is `JSON.parse(data).result.status` but if you look at the log of the site it shows the JSON is appended at the end after some html in `result` – Class Mar 23 '14 at 03:58