Thursday, September 22, 2011

Errors should never pass silently

 - The Zen of Python


Lately, I have been programming a lot in Javascript, and have come to appreciate even more what Tim Peters expressed so well in writing what is now known as The Zen of Python.  In particular, I appreciate the philosophy that "Errors should never pass silently."

Those that don't care about Javascript can stop reading now.  Others may benefit, and perhaps even enlighten me even further, about a "feature" I came across.

I'm working on a new website which will include only interactive tutorials.  [No, not Crunchy-based ones, but honest-to-goodness interactive tutorials that require nothing but a browser.]   To make my life easier, I use jQuery as well as CodeMirror.  A user can edit the code in the CodeMirror editor and view the result "live" in a separate window (html iframe).  Every time the content of the editor is changed, the iframe gets updated, as illustrated here.

I started by using the standard $ jQuery notation inside the html iframe without including a link to jQuery in the iframe, since I already included it in the parent page, and got an error in the console to the effect that $ was not defined.  Fair enough.  I changed the source to also include a link to jQuery inside the content of the editor (to be copied in the iframe) and the error vanished.  However, no javascript code was run from the iframe, not even a simple test alert.  Meanwhile, the javascript console remained silent.

Errors should never pass silently.

Eventually, by searching on the web, I was able to find a solution.  However, before I found a solution, I encountered a truly puzzling "feature".

After including a link to jQuery in the editor (which then was copied into the iframe) and reloading the page, if I then proceeded to remove that link from the editor, suddenly all javascript code embedded in the iframe, including all jQuery calls, would work.

I can just imagine giving these instructions to beginners:
We are going to use jQuery, as you can see from the code in the editor.  Now, to begin, you have to select the line where jQuery is loaded and delete it so that the browser (iframe) can use it. 
I still have not figured out how that phantom jQuery worked... and strongly believe that some error message or warning should have appeared in the javascript console (for Chrome, or Firebug for Firefox).

In any event, to solve my problem, I had to do 3 things:

  1. Only load jQuery once, in the main window.
  2. Write $ = parent.$; inside the iframe before using the $ notation.  
  3. As I wanted to draw things on a canvas, replace the usual $("#canvas") jQuery idiom by $("#canvas", document) everywhere.

Now everything appears to work just as expected.