Search code examples
javascriptevaladdeventlistenerevent-listener

What is the alternative to using eval(myFunctionName) as a callback in an Event Listener?


I set about asking this question wrongly, so I am starting again, beginning with the specifics of the issue I am wrestling with, rather than the general features of the issue.

I have an object in which the values are strings. They pretty much need to be strings because they are extracted from HTML5 custom data-* attributes and I really don't want to start writing javascript inside HTML attributes, like it's 1999.

Here's an example of one of the custom data-* attributes:

data-event="{«eventListener» : «transitionend», «eventAction» : «showText»}"

As you can see, it's basically a JSON string, slightly modified, so that it can take the form of an HTML attribute value.

I would like to be able to parse that custom data-* attribute and translate it into the following javascript:

parentElement.addEventListener('transitionend', showText, false);

To do this, I need to:

  1. Replace the « and » characters with the " character
  2. JSON.parse the resulting value into an object
  3. Create the useCapture parameter if it doesn't exist (as in this example)
  4. Then it's straightforward (almost) for me to create the addEventListener statement

In fact - of course - I end up with this statement:

parentElement.addEventListener('transitionend', 'showText', false);

which doesn't work because I can't invoke 'showText' - it's just a string, it doesn't point to a function.

The easiest way to fix this is to create this statement, instead:

parentElement.addEventListener('transitionend', eval('showText'), false);

which is equivalent to:

parentElement.addEventListener('transitionend', showText, false);

The only thing that's holding me back is my uncertainty over whether eval() should really never be used or whether it should simply mostly be avoided - and, despite normal warnings, this unusual situation is an acceptable situation in which to deploy eval().


Question: Is it misguided or inadvisable in Javascript to take a string which happens to be the name of a function and to access and execute that function by using eval() on the string?

If it is inadvisable, what is the alternative, when I know the name of a function and I wish to insert it into an event handler?

If I'm better off avoiding this:

parentElement.addEventListener('transitionend', eval('showText'), false);

what should I be using instead?

Or... is it entirely acceptable to use eval() in some situations - and this is one of them?


Solution

  • In response to the update, you will be better off placing all event handlers in an object instead of the global namespace, that is:

    before:

    function showText(event) {
       ...
    }
    
    function anotherHandler(event) {
       ...
    }
    

    after:

    const myActions = {
       showText(event) {
          ...
       },
       anotherHandler(event) {
          ...
       }
    }
    

    And then, after you've parsed the data attribute and got something like this:

    data = {"eventListener" : "transitionend", "eventAction" : "showText"}
    

    bind the handler this way:

    parentElement.addEventListener(
         data.eventListener,
         myActions[data.eventAction],
         false)
    

    This not only gets rid of eval, but also helps organizing your code in a cleaner way.