0

I want to be able to do this

$('.class').bind({'click':'function(){ ... }'}); // note that the value is a string

and somehow, checking inside a hooked "bind", that it's indeed a function, and eval() or new Function the string, so it will be correctly assigned as an event.

The reason I want to do this is because JSON doesn't allow functions to be defined as values, only strings/ints. I would want to find a way to apply this for all jquery functions (like animate(), click(), live(), etc) that take a handler/function as parameter. it would be a huge hassle and I think, and would become impractical after each new version of jQuery released

Or is there any better way to accomplish this? checking for the first 8 characters if they are === 'function' and then eval it is not a good idea, since it can be a "legitimate" text string. I tried passing a function as a result from a ajax JSON response, but $.parseJSON failed silently.

pocesar
  • 6,860
  • 6
  • 56
  • 88
  • **JSON** string, not javascript lol – pocesar Mar 09 '11 at 02:07
  • 8
    **Why are you doing this?** – Hello71 Mar 09 '11 at 02:11
  • I want to be able to pass anonymous functions from PHP to Javascript, through JSON, without having to register a global named function before doing the request – pocesar Mar 09 '11 at 02:19
  • try passing a function through a JSON string and using $.parseJSON on it. it's not allowed (and this is per spec) – pocesar Mar 09 '11 at 02:22
  • ahhh never mind... the problem is not really clear if you ask me... – Reigel Gallarde Mar 09 '11 at 02:23
  • by the way, I'm coming with a weird solution lol. I'm using `String.prototype.apply()` and `String.prototype.call()` to eval() the string (if you call `"function(){ alert('blah'); }".apply();`), but isn't working so far. @Reigel: english isn't my primary language, sorry about that – pocesar Mar 09 '11 at 02:25
  • 1
    If you are going to `eval` the string, **just bleepin' `eval` it, mate.** – Matt Ball Mar 09 '11 at 02:36

2 Answers2

0

Just found my own answer, WOW, javascript can be quite powerful, check this out

var call_cache = [];

str_is_function = function(str){
  if (jQuery.type(str) !== 'string' || ! /^\s*?function/i.test(str) || ! /\}$/m.test(str)) return false;
  return true;
}

String.prototype.apply = function(obj){
  if ( ! str_is_function(this) ) return false;

  var str = this.toString(), cache_len = call_cache.length;
  fn = null;

  for(i = 0; i < cache_len; i++){
    if (call_cache[i].str === str) {
      fn = call_cache[i].fn;
      break;
    }
  }

  if (typeof fn != 'function'){
     $.globalEval('var fn = ' + str);
     call_cache.push({'str': str, 'fn': fn});
     cache_len = call_cache.length;
  }

  args = Array.prototype.slice.call(arguments, 1);

  if (typeof args[0] != 'undefined' && args[0].constructor === Array){
    args = args[0];
  }

  return fn.apply(obj, args);
}

String.prototype.call = function(obj){
  this.apply(obj, Array.prototype.slice.call(arguments, 1));
}

$('.gap').bind({'mouseover':'function(){ alert("gi");}'});

"function(name){ alert(name); }".call(null, "hi");
"function(name){ alert(name); }".apply(null, ["hello"]);
"function(){ alert('teehee'); }".call(null);
"alert".call(null, "hi"); // wont work

No need to hook any jQuery specific function. When it tries to call() or apply() on a string, it will eval to code/function. the problem is that this is a global modification, and could lead to some client-side havoc if someones find out about it hehe.

what are the caveats in this solution?

pocesar
  • 6,860
  • 6
  • 56
  • 88
  • by looking at jquery dev source http://code.jquery.com/jquery-1.5.1.js almost all parameters that are considered callbacks and handler/functions are called through either call() or apply(). That's exactly what I need, but I need to understand the implications of this `String.prototype.apply`, if there's any real security concern, knowing that most of the time, the call will happen from a controlled source (from inside a PHP controller, through json_encode()'ed variables) – pocesar Mar 09 '11 at 03:13
0

Is this what you are looking for, http://jsbin.com/adewe4/3

function definition https://gist.github.com/862112

You can use the parseJSONwithFunctions method to parse the JSON data that you receive as the AJAX response using $.getJSON.

parseJSONwithFunctions converts the function body as strings in the JSON into actual function objects; so rather than trying to make jQuery eval strings, you can just pass the function reference to it.

If you use the method as,

var my_json_data = {};

$.getJSON('URL_TO_GET_JSON', function (data) {
  my_json_data = parseJSONwithFunctions(data);
});

and the you can define handlers as,

$('.class').bind('click', my_json_data.clickHandler);
Livingston Samuel
  • 2,422
  • 2
  • 20
  • 35