views:

82

answers:

4

Some information - I'm creating an autocomplete which gets the data from a json feed. The JSON part works fine and the result is valid.

When I'm obtaining it, I'm using json2.js and running JSON.parse. When I try and output it tells me that it (the object containing the parsed JSON text) is actually undefined.

If I run an alert on the object and then output it works. It's probably something quite simple. But this is the bit that is confusing as it works fine if I alert the object

I know that it won't work on everything, I'm just trying to get it working for now and I'll improve it.

Thank you and if there is any more information I can provide I will.

The code

//sURL takes a search term that's passed into the function

var JSON_object = {};
var oRequest = new XMLHttpRequest();
var sURL  = "datalinkhere"+input.value;

oRequest.open("GET",sURL,true);
oRequest.setRequestHeader("User-Agent",navigator.userAgent);
oRequest.onreadystatechange = function () {
    if (oRequest.readyState == 4 && oRequest.status == 200)
    {
        JSON_object = JSON.parse( oRequest.responseText );
    }
};
oRequest.send(null);

suggestion(JSON_object,input);

function suggestion(inp,targetid)
{
    document.getElementById('autosuggest').style.display='block';
    document.getElementById('autosuggest').innerHTML=inp[1].namefield;
}
+1  A: 

Try JSON_object = eval(oRequest.responseText);

yogs
`eval()` is almost always a bad idea.
Ignacio Vazquez-Abrams
@Ignacio - in a browser that does not have native JSON support (which is still most of them at this point), how would you load a JSON object without using `eval()`?
Andrew
@Andrew: With json2.js.
Ignacio Vazquez-Abrams
Sure, you can use `eval` for parsing JSON. Yeah, you'll be in trouble if it contains arbitrary JavaScript instead of JSON values, but then if your server is returning dodgy JavaScript you've got much worse security problems to worry about. **But** if you do use `eval`, you'll need to wrap the `responseText` in brackets (to avoid object literals being parsed as blocks), and replace any occurrences of characters U+2028 and U+2029 with escapes, because they're valid in JSON but not in JS string literals. `eval('('+responseText.split('\u2028').join('\\u2028').split('\u2029').join('\\u2029')+')')`.
bobince
@bobince - exactly. There is no intrinsic danger in `eval()`, but how it's used in accepting 3rd party data. JSON2.js -- which uses `eval()` itself -- simply takes care of the complexity of cleansing your data. I personally feel that if you control and generate the data yourself, there's no risk to using `eval()`.
Andrew
I agree. Obviously you should go for native `JSON.parse` first if it exists, only using the `eval` as a fallback.
bobince
If the OP's auto-complete system allows for dangerous strings to get into his JSON, `eval()` would be dangerous regardless. So would JSONP. Potentially, so could XML via AJAX. But if you control the JSON string and cleanse the data going out to the client, `eval()` should be as safe as inline code. Using `JSON.parse()` is an added layer of security that you shouldn't even need. The whole `eval is evil` mantra just gets under my skin. It's like saying, "Never use knives because they'll cut you." Well, a) not if you're careful and b) ever try eating pork chops with a spork?
Andrew
I do control the json so using eval would probably be okay. I wasn't sure though so used json parse
Paul
+1  A: 

The problem ist not alerting the json or not it's the concept of your code. Ajax requests work asynchronously, thus your oRequest.send call will not block until the data has been loaded, the data is loaded in the background.

So you can have luck and the data is available when the next line (suggestion-call) and your code works or you will get an undefined var.

You'll have to write your code asynchronously: Put the suggestion-call direcly after the JSON.parse-call and all will work like a charm.

Tobias P.
Thank you both. Tobias, that sorted it. Thank you very much and I will accept the answer in 5 minutes when it allows me.
Paul
+1  A: 

You might be interested in the function that jQuery uses:

parseJSON: function( data ) {
    if ( typeof data !== "string" || !data ) {
        return null;
    }

    // Make sure leading/trailing whitespace is removed (IE can't handle it)
    data = jQuery.trim( data );

    // Make sure the incoming data is actual JSON
    // Logic borrowed from http://json.org/json2.js
    if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
        .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) {

        // Try to use the native JSON parser first
        return window.JSON && window.JSON.parse ?
            window.JSON.parse( data ) :
            (new Function("return " + data))();

    } else {
        jQuery.error( "Invalid JSON: " + data );
    }
}

There are a couple of jQuery methods in there, namely trim and error, you can find out what they are by reading the source: http://code.jquery.com/jquery-1.4.2.js

The interesting part is this bit:

// Try to use the native JSON parser first
return window.JSON && window.JSON.parse ?
    window.JSON.parse( data ) :
    (new Function("return " + data))();

It's a neat way of reading the JSON without using eval - setting up a function that returns the data.

Rich Bradshaw
The Function constructor still ends up using eval. I really wonder what the benefit of that self calling function is...
Juan Mendes
Hmmm, I'm not 100% sure... I'll find out and post here.
Rich Bradshaw
Ah: "Function( 'return ' + data )() is also MUCH faster in Firefox than eval. In a test case of JSON data containing 1000 names and addresses (about 112KB), eval() takes a full second to execute on my machine in Firefox 3. On all other browsers (including IE!) it takes hardly any time at all. The Function version takes essentially no time in Firefox. (Didn't test it in other browsers.) " (http://groups.google.com/group/jquery-dev/browse_thread/thread/f441058133cf07be/)
Rich Bradshaw
From same thread John Resig says: "That's specifically being done to allow YUIMin to properly compress jQuery (it sees an eval and assumes that it can't be compressed, but using that technique allows it to work)."
Rich Bradshaw
A: 

The best JavaScript which do it is JSON.parse function from json2.js which you can downloads from http://www.json.org/js.html. It is the most official version of JSON.parse and JSON.stringify. By the way the implementation verify whether the web browser hat internal implementation of these functions and use these if they exists.

Oleg