views:

8069

answers:

2

We have an application with legacy code that relies on prototype, but we've found it to be too 'heavy' for most of the places we want to use it and and have found jQuery to be a better fit for how we work. So we're migrating to jQuery for new functionality.

In the meantime we have several pages that need to load both libraries:

<script language="javascript" type="text/javascript"
        src="prototype-1.5.1.2.js"></script> 
<script language="javascript" type="text/javascript"  
        src="jquery-1.3.2.js"></script> 
<script language="javascript" type="text/javascript">
    $j = jQuery.noConflict();
</script>

(note older version of prototype, we found issues on upgrading that we don't want to fix when we're phasing it out anyhow)

This works in IE6, IE7, IE8-as-7 and FX3, but load it in Chrome and all the jQuery stuff fails.

Loading up the developer javascript console displays the following errors:

Uncaught Error: NOT_SUPPORTED_ERR: DOM Exception 9 http://.../prototype-1.5.1.2.js (line 1272)
Uncaught TypeError: Object #<an Object> has no method 'ready' http://.../lib.js (line 161)
Uncaught TypeError: Object #<an Object> has no method 'slideUp' http://.../page.aspx (line 173)
... and so on - all the failures are missing jQuery methods

So this looks like a conflict in prototype that causes the creation of the jQuery object to fail.

The specific prototype issue appears to be Prototype.BrowserFeatures.XPath being true when it shouldn't be, as XPath document.evaluate isn't supported.

Ok, so now reload the page with the javascript console open - it all works! WTF? Close the console, reload and it fails again.

The failure only occurs when the page load occurs without the javascript console open - why would that make any difference? That looks very much like a bug in Chrome.

Anyone able to explain what's going wrong? Why should an error in prototype cause the jQuery init to fail? Why does loading the page with the console open make it work?

Anyone know a good workaround? (apart from upgrading to prototype-1.6.0.3.js, which fixes this issue but breaks a load of legacy code elsewhere)

+18  A: 

From Core/jQuery.noConflict:

NOTE: This function must be called after including the jQuery javascript file, but BEFORE including any other conflicting library, and also before actually that other conflicting library gets used, in case jQuery is included last. noConflict can be called at the end of the jQuery.js file to globally disable the $() jQuery alias. jQuery.noConflict returns a reference to jQuery, so it can be used to override the $() alias of the jQuery object.

Maybe try changing it to:

<script language="javascript" type="text/javascript"
  src="jquery-1.3.2.js"></script> 
<script language="javascript" type="text/javascript">
    $j = jQuery.noConflict();
</script>
<script language="javascript" type="text/javascript"
  src="prototype-1.5.1.2.js"></script>
jakemcgraw
That works, thanks. Any idea why the Chrome console fixes it too?
Keith
Using any kind of debugging tool (especially in-browser JavaScript tools) will cause code to execute in different way, "What we observe is not nature itself, but nature exposed to our method of questioning." (Heisenberg, Physics and Philosophy, 1963). Also, don't forget to accept my answer!
jakemcgraw
+1 this helped me too. I'd like to point out there is conlflicting documentation to me careful of: http://docs.jquery.com/Using_jQuery_with_Other_Libraries
blu
this is not always the case, and many times you have no control over the scripts in the page, lets say, if you make some sort 3rd party service which users add to their site/blog.
vsync
+3  A: 

I've found the root of this problem to be:

1) Prototype loads, and because WebKit lacks document.getElementsByClass(), Prototype (insidously) creates it.

2) JQuery initialization begins, and at the very top, it sets window.$ to jQuery.

3) During JQuery's initialization, the Sizzle engine (added in 1.3.2?) initializes. As part of its introspection, it checks for, and then tests the functionality of document.getElementsByClass(). As a result, it calls Prototype's impelementation of getElementsByClass(), which depends on window.$ being set to Prototype's $, not jQuery's.

Ultimately, this will need to be fixed in jQuery (see tickets http://dev.jquery.com/ticket/4365 and 5027). My quick patch was to remove the assignment to window.$ in the top of jQuery's initialization.

hblanks
This is indeed the problem. as someone mentioned in the ticket, there's a section that can be wrapped in try/catch so go around this.
vsync