Is this a really bad idea?
I'm currently working on a pretty complicated mobile/web app based on jQuery Mobile, which pulls in pages using AJAX, and uses it's own system for caching/removing pages. I've recently found myself wanting to be able to attach a script directly to a particular element in a page, which isn't something that's currently possible.
(When I say page here, I really mean a jQuery Mobile <div data-role="page"> element, being loaded via AJAX, rather than a full, "real" page)
As it stands right now, one way to run a script on that element would be to include a <script> block within the page in question, which refers back to the element using its ID. Normally this would be fine, but in my case it's possible that the page could transition to an updated copy of itself, which would (temporarily) result in that element ID no longer being unique within the overall document - and this would probably target the old one. Another (possible) drawback with this method is having to include a script tag within the page element - I'm not sure how this affects performance etc, but it just feels a bit odd to me.
The other solution is to use "live" or "on" to listen for the "pagecreate" or "pageinit" event being triggered for the ID of the page in question, and run the code there using "this" (i.e. the page) as the context for the jQuery selector for the element, to ensure it finds the one within the newly created copy of the page. This is what I'm currently doing, which works fine, but it means having to include the code for all such elements (in all pages) in my global js file, and those bindings are also always enabled, even if the user never loads that particular page.
So today I decided to see if it would be possible to attach some code directly to an element, and have it execute in the context of that element, when the page is loaded. It actually turned out to be extremely simple to achieve:
- $(document).bind("pagecreate", function(e){
- $(e.target).find("[oncreate]").each(function(){
- eval($(this).attr("oncreate"));
- });
- });
It's then possible to add an "oncreate" attribute to any element within a page, which will run when the page is loaded, within the context of that element (i.e. "this" will refer to the element itself). Which seems a whole lot neater to me (and not to mention more convenient), at least in certain cases.
Now, I know it uses eval(), which is generally seen as extremely bad, evil, etc... but is it really that bad in this case? If so, what are the reasons? Possibly security implications? (if someone can inject code into the page being returned by the server, or somehow cause an external page to be loaded via AJAX, then they could cause arbitrary code to be executed within the document... but if they can do that, surely they could just as easily include a script tag, so I'm not sure that holds up).
If eval() is really that bad even for this type of use case, another option would be to instead have an attribute which specifies a function to be executed in the context of the element. This is possible without having to use eval() at all, but re-introduces some of the drawbacks of the previous solutions - namely having to include the function either within a script tag in the page or in the outer "real" page (or a global js file included there). This also doesn't appear to be much faster than using eval() as above.
Failing both of those, the element attribute(s) could contain the names of functions to bind to specific events (e.g. click), basically creating a fully jQuery-based version of the standard onClick attribute. This is obviously a lot less flexible (and possibly slower on each pagecreate if looking for other events too), but does seem to be a bit faster than either of the above and should be better than mixing standard onClick attributes with jQuery Mobile (which is not something I'm currently doing, but I know people do, sometimes with unexpected results).
I've used jsperf to try to compare the speed of all these different methods. It's probably not a very good overall test, as it doesn't test the differences in event bindings etc, but it was mainly just to see if eval() was really that much slower than the other methods of attaching something directly to an element. I also seem to be getting different results every time I run it now (sometimes the onclick function coming out slower than the named function to run), so I'm not sure it's that much help at all.
Any thoughts on all this?