2

If I define a JavaScript code snippet in my HTML, like so:

<div id=myElem onMyUpdate="alert('Update called for ' + this.id)">...

then what is the most elegant way of evaluating it from within JavaScript with this properly assigned?

What I came up with so far is something like this:

if (elem.hasAttribute('onMyUpdate'))
    (function () { eval(elem.getAttribute('onMyUpdate')) }).call(elem);

which looks terrible (to me), but works. Any better/more elegant alternatives?

MDN says there used to be the second argument to eval() for doing just that but it's deprecated now; MDN then suggests to use operator with() instead, which, if you follow the link provided, turns out to be made deprecated by the latest standard. Dead end, in other words.

(As a side note, StackOverflow ignores the word this in search terms and thus it may miss relevant answers - is there a way of telling it not to?)

Edit: I forgot to mention: no jQuery please, just vanilla JavaScript

mojuba
  • 11,842
  • 9
  • 51
  • 72

4 Answers4

2

How about this:

if(elem.hasAttribute('onMyUpdate')) {
  var fun = new Function(elem.getAttribute('onMyUpdate'));
  fun.call(elem);
}
geocar
  • 9,085
  • 1
  • 29
  • 37
  • 1
    Note the use of `new Function()` instead of `eval()` – geocar Sep 30 '12 at 20:58
  • Actually the Function constructor **is** a form of eval. – rsp Sep 30 '12 at 20:59
  • 1
    Actually it isn't. Consider `function foo(x) { function bar(y) { eval("x += y;"); return x; } return bar; }` versus `function foo(x) { return new Function("x += arguments[0]; return x;"); }` – geocar Sep 30 '12 at 21:03
  • Ah, sorry, didn't notice that. Now I like it! And I'd rather write it as: `Function(elem.getAttribute('onMyUpdate')).call(elem)`. That's it, accepted, and thanks ;) – mojuba Sep 30 '12 at 21:05
  • 1
    @geocar I didn't say that it is exactly identical to eval but that it is **a form** of eval. The scope is different but you are still parsing and `eval`uating code stored in text. It's just like passing strings to setTimeout or setInterval is a form of eval, even if obviously it's not the same. – rsp Sep 30 '12 at 21:09
  • I'd appreciate if you incorporated my short version into your answer, perhaps as an alternative, as `new` is not really required here, and overall it looks neat as a one-liner. Cheers ;) – mojuba Sep 30 '12 at 21:12
  • 2
    @rsp - Mozilla recommend [Function](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function) over [eval](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/eval): *... More importantly, third party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways of which the similar Function is not susceptible.* – geocar Sep 30 '12 at 21:13
  • It's "a form of eval" in exactly the same way `document.createElement` is a form of eval: Technically correct but completely unhelpful. – geocar Sep 30 '12 at 21:14
  • @mojuba - I don't like the function-call form of `Function()` because it's easy to misread as `function()`, and because `Function()` is uncommon: A junior programmer is much more likely to be able to google `new Function()` than `Function()`. – geocar Sep 30 '12 at 21:18
  • 1
    @geocar I also recommend the Function constructor over eval. No disagreement here. I just happen to recommend custom events over the Function constructor in this case. The only difference with eval and the Function constructor is the scope. With custom events you don't parse strings and evaluate them as code, like you do with both eval and the Function constructor (and string versions of setTimeout or setInterval). See the answer by Sidharth Mudgal for an elegant solution. – rsp Sep 30 '12 at 21:18
  • @rsp - There's nothing wrong with parsing strings and evaluating them as code: Code is data and data is code. Pretending that the bits are coloured differently when they're in a `.js` file is just naive. – geocar Sep 30 '12 at 21:34
  • @geocar I'm not saying that your solution doesn't work or that bits are colored differently. As a matter of fact as a big fan of meta-circular evaluators I'd love to see eval in JavaScript be even **more** powerful. The question though was asking for more elegant alternatives and I vote for custom events here. See [this question](http://stackoverflow.com/questions/86513/why-is-using-the-javascript-eval-function-a-bad-idea) for more info on potential problems with eval and the Function constructor. – rsp Sep 30 '12 at 21:44
  • @rsp - Great. Good luck with that. I think `new Function()` is more elegant. – geocar Sep 30 '12 at 21:51
1

Ideally, you should do this completely unobtrusively, and without the use of eval:

<div id="myElem"></div>

.

var elem = document.getElementById('myElem');
elem.onMyUpdate = function () {
    alert(this.id);
};

// ...

elem.onMyUpdate && elem.onMyUpdate();
Andreas Grech
  • 105,982
  • 98
  • 297
  • 360
  • As I said in the question, the code is embedded in the HTML tag and can't be moved - by design. – mojuba Sep 30 '12 at 20:57
  • 1
    Where did you say that it can't be moved by design? – Andreas Grech Sep 30 '12 at 20:59
  • The question goes: if I have X, what is the way of doing Y? That implies X can't be changed, right? ;) – mojuba Sep 30 '12 at 21:10
  • 1
    Well, not really...just because you currently have a design, doesn't mean that that design can't be changed, and the question gave no indication that there was no room for amendments. – Andreas Grech Sep 30 '12 at 21:13
  • In my case changing the design would mean creating a separate extra ` – mojuba Sep 30 '12 at 21:15
  • 1
    I hope I'm not being too brash here, but incorporating JavaScript code within your HTML markup is in fact a bad decision, primarily because you're mixing behavior with presentation, amongst other reasons (like caching, progressive enhancement and so on...). – Andreas Grech Sep 30 '12 at 22:27
  • 1
    Embrace the ` – Andreas Grech Sep 30 '12 at 22:29
  • It's OK, I'm friends with the ` – mojuba Sep 30 '12 at 23:46
0

A more elegant solution would be to use custom events, bind handlers to some custom events on your HTML elements and trigger them in some other parts of your code. See this tutorial and the answer by Sidharth Mudgal for some examples.

Community
  • 1
  • 1
rsp
  • 107,747
  • 29
  • 201
  • 177
  • I know I can have custom events with or without jQuery, but the whole point of my question is: what if I define some JavaScript code in HTML, and then some library code calls my snippet directly using eval? – mojuba Sep 30 '12 at 20:59
  • Well, you asked for a more elegant solution, which would be using custom events. See [this question](http://stackoverflow.com/questions/86513/why-is-using-the-javascript-eval-function-a-bad-idea) for more info on why eval is not considered elegant. – rsp Sep 30 '12 at 21:05
  • eval/new Function wins over Custom events? Absolutely astonishing. Upvoted. – Phil Jul 02 '15 at 20:27
0

Instead of using this you can use elem.

 <div id=myElem onMyUpdate="alert('Update called for ' + elem.id)">...

js:

if (elem.hasAttribute('onMyUpdate')){ // all variable available here will be available inside eval.
     eval( elem.getAttribute('onMyUpdate') );
}
Anoop
  • 23,044
  • 10
  • 62
  • 76