6

I have a JSON string which includes a function I need to call.

My JSON looks like this:

{  
    "type":"listview",
    // the function I would like to call
    "content":"dynoData.getRetailers()",
    "custom_classes":["","nMT pickList","",""],
    "lib":"static_listview.html",
    "tmp":"tmp_listview_inset",
    "lang":"locale_search",
    ...

I'm using this to assemble a jQuery Mobile listview on the client. To get the dynamic data, I need to call dynoData.getRetailers().

However I'm struggling to make the call :-)

This is what I'm trying:

var dyn = $.parseJSON( passed_JSON_string ),
    content = dyn.content;

I had hoped calling it would trigger the function but it just returns the function name as a string.

Question:
How can trigger the actual function?

Thanks!

EDIT:
I'm putting the JSON string on the HTML element on the actual page, which I will replace with the element I'm building. Here is the HTML:

<ul data-template="true" data-config='{  
    "type":"listview",
    "content":"dynoData.getRetailers()",
    "custom_classes":["","nMT pickList","",""],
    "lib":"static_listview.html",
    "tmp":"tmp_listview_inset",
    "lang":"locale_search",
    "theme":"c",
    "filter":"true"
    }'></ul>

I could put all of these into data- attributes, but that would be messy...

Solution: This worked:

1) change JSON to:

..."method":"getRetailers", ...

2) call from Javascript:

content = dynoData[ dyn.method ]();

Thanks everyone!

frequent
  • 27,643
  • 59
  • 181
  • 333
  • Have you tried using `eval()` – Brett Gregson Dec 09 '12 at 22:07
  • 1
    No, because I'm told `eval is evil`. I never use. Is there another way? – frequent Dec 09 '12 at 22:07
  • can you change the json, to avoid using `eval()` ? – charlietfl Dec 09 '12 at 22:09
  • hm. change to what? Wait I post my HTML, which contains the JSON string. – frequent Dec 09 '12 at 22:09
  • Is the function that you need to call dynamic or will it always be that same function? I like your eval is evil, lol, I must remember that :) – Brett Gregson Dec 09 '12 at 22:10
  • the function is always the same. – frequent Dec 09 '12 at 22:12
  • You could just check for a specific value instead of the function name, and then call the function (hard coded) – Brett Gregson Dec 09 '12 at 22:16
  • @eskimo: I'm trying that just now. – frequent Dec 09 '12 at 22:19
  • So you want to run some JavaScript code you pass, but you don't want to have it eval'd. There's a problem. All JS that runs is effectively eval'd. If it wasn't, it wouldn't run. If you're going to execute some code, that means you're going to execute some code. It'll be up to you to ensure that it isn't malicious. – I Hate Lazy Dec 09 '12 at 22:26
  • @IHateLazy: I'm trying to live by [this](http://stackoverflow.com/questions/86513/why-is-using-the-javascript-eval-function-a-bad-idea). Since I'm targeting slow mobile devices, I'm not touching eval (otherwise I would have used the JQM widget out-of-the-box long time ago :-) – frequent Dec 09 '12 at 22:29
  • Yes, but ultimately you're going to execute some code from input that can't be known by the "compiler". Somehow I doubt that reading object properties will make much difference. Can't say for certain without testing I guess. – I Hate Lazy Dec 09 '12 at 22:32

4 Answers4

5

Assuming the function is always part of the dyn object you can use notation like following to call a function:

dyn['dynoData']['getRetailers']();

So if you are able to adjust json you could send back something like:

"content":{ "mainObject": "dynoData" , "method" :"getRetailers"}

And translate it to your dynamic function using variables:

  dyn[content.mainObject][content.method]();

As an example using jQuery try using the following :

$('div')['hide']();

Which is the same as :

$('div').hide()
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • ah. That looks nice, too. Will try. Thanks – frequent Dec 09 '12 at 22:18
  • thanks, but this way is only for call method in an object. It has to force write callback method in below way: var callbacks = function() { var method = function() {}; return {method1 : method}; }(); – Bob Bao Apr 01 '16 at 03:46
1

As charlietfl pointed out you can use object notation to call functions. For your case you have to get rid off () and split it, then call it like this;

jQuery(function($) {
    var temp = $('ul').data('config').content.replace(/\(\)/g, '').split('.');
    window[temp[0]][temp[1]]();
});

However this could solve your problem, if you think about future, you have to extend it a little bit. This way even you don't know the depth, you can call it anyway;

jQuery(function($) {
    var temp = $('ul').data('config').content.replace(/\(\)/g, '').split('.'), func, i, il = temp.length;
    for(i = 0; i < il; i++) {
        if(func == null) {
            func = window[temp[i]];
            continue;
        }
        func = func[temp[i]];
    }
    func();
});
Emre Erkan
  • 8,433
  • 3
  • 48
  • 53
1

Try ConversationJS. It makes dynamic calls pretty easy and its a great way to decouple your codebase: https://github.com/rhyneandrew/Conversation.JS

Andrew Rhyne
  • 5,060
  • 4
  • 28
  • 41
  • ah. I will have to take a look. Spaghetti script it is... :-) – frequent Dec 09 '12 at 23:23
  • Conversation will actually help you prevent spaghetti because none of the functions are explicitly called. Instead, they are "spoken to" by sending a string that they are "listening for". It's pretty cool – Andrew Rhyne Dec 09 '12 at 23:27
0

JSON is purely data notation to be passed around so it is easily read and parsed, therefore it has no concept of functions. However, there are other ways of dealing with this and if you are starting to think that that is the only way to deal with your dilemma, then take a step back and examine your design. Instead of using this:

eval(yourCode);

Try this

var tempFun = new Function(yourCode);
tempFun(); 
ian
  • 149
  • 6