Julian Bogdani
Julian Bogdani

Reputation: 399

prototypejs 1.6 to 1.7 json problems

I had a json parsing problem updating my app from prototype 1.6.1 to 1.7.0 This is a very simplified model of my json as it, saved in tmp.js:

{
"text":"hello world",
"fn": function(){alert('hello world')
}

and this is my code:

new Ajax.Request('tmp.js', {
onSuccess: function(transport){
    var json = transport.responseText.evalJSON();

    var button = new Element('button')
            .update(json.text)
        .observe('click', function(){
            json.fn();
        });
    $('my_div').update(button);
}});

All this worked correctly with 1.6.1: it produced a button that alerted 'hello world' on click. This does not work in v. 1.7.0, because of the fact that my json is not valid. I know it should not contain functions, but only data.

My question is: why did it worked with 1.6.1 (and still works) and is there a way to accomplish the same with 1.7.0. I need to get via ajax a js object containing user defined functions.

Thank you

Update: The reconstruct function is a good solution and I think I'll use it in the future. Anyway I found eval() function that seems to be a good and fast solution:

tp.js JSON:

{
"text":"hello world",
"fn": "my_alert('hello world')"
}

JS

function my_alert(string){
    alert(string);
}

new Ajax.Request('tmp.js', {
onSuccess: function(transport){
    var json = transport.responseText.evalJSON();

    var button = new Element('button')
            .update(json.text)
        .observe('click', function(){
            eval(json.fn);
        });
    $('my_div').update(button);
}});

Upvotes: 0

Views: 1727

Answers (1)

Pointy
Pointy

Reputation: 413757

What you've got in that sample data you posted is not JSON. In strict JSON the value of a property can be

  • a string
  • a number
  • boolean true or false
  • null
  • an array
  • an object

There is no way to include a function definition in JSON. (Well, that's not exactly true; you're free to use strings, numbers, arrays, objects, etc. to describe a function in such a way that your code can reconstruct it after the JSON is parsed. The point is that straight JavaScript function expressions are disallowed.)

One simple, slightly disturbing thing you could do is save the function body as a string, and then reconstruct it by calling

foo.fn = new Function(foo.fn);

once the JSON parse is complete.

edit more details:

The "Function()" constructor takes as its arguments a list of strings representing argument names, followed by a string that's to be used as the function body. If you wanted to encode a complete JavaScript function, therefore, you might want to have it look like an object:

{
  'foo': 'plain property',
  'someFunction': {
    'arguments': [ 'x', 'y' ],
    'body': 'if (x > y) return "x"; return "y";'
  }
}

Now to turn "someFunction" into a real function, you'd use something like this:

function reconstructFunction(descr) {
  var params = (descr.arguments || []).slice(0);
  params.push(descr.body);
  return Function.apply(null, params);
}

Then you can just pass the function descriptor from your JSON into something like that, and then you have a bona fide JavaScript function to call.

Upvotes: 1

Related Questions