ADDED DETAILS: The problem appears only on those VF pages where a custom homepage component uses another version of jQuery. Those component seems to load later and overwrite the jQuery object that was extended by BlockUI before. That's why any calls to
$(node).block()
show errors that function "block" cannot be found.
I'm experiencing constant problems when using Jquery in combination with the famous BlockUI plugin.
It only seems to appear on more complex VF pages that:
- Have embedded Javascript
- Include external Javascript
- Have embedded VF components also include jquery and BlockUI
In the past I thought that using jquery.noConflict()
like below:
<script type="text/javascript">
$j = jQuery.noConflict();
$j(document).ready(function() {
and <apex:includeScript>
instead of <script>
would take care of all this multiple loading issues that one might think of.
But BlockUI as a plugin seems to extends the Jquery operator by adding function with $j.fn.
.
In complex pages when I call blockUI I receive the error that $j.fn.block cannot be found.
Is there a best practise for resolving conflicts with pages that load the same Javasript library multiple times?
- Should I rename $j in every place?
- Should I dynamically load
libraries by using$j.getScript('{!$Resource.jquery_blockUI_js}');
Best Answer
jQuery plugins, as a best practice, should be registered on the main
jQuery
object, NOT on$j
or other alternative references to jQuery obtained through use ofjQuery.noConflict()
.Depending on when/how various jQuery plugins are loaded in the page, this will make the plugins available to all alternate jQuery references (e.g. one developer's code might use
$j = jQuery.noConflict()
, another's might usej$ = jQuery.noConflict()
), but they will all have access to all jQuery plugins registered throughout the page load on the main jQuery object.To properly register the
blockUI
plugin, use the code from the plugin's download page --- this registers the plugin on thejQuery
global object by, essentially, registeringjQuery.fn.block = function(){}, jQuery.fn.unblock = function(){},
etc. However, this code attaches/registers its plugin within a CLOSURE, so its reference to thejQuery
global object is locked in. DO NOT register plugins on a unique reference (that is, do NOT do$j.fn.pluginName = function(){})
--- always register plugins on the main jQuery object.TO avoid reloading a given jQuery plugin multiple times, you could check for the plugin's existence before loading:
Finally, as an aside, all that
jQuery.noConflict()
does is to relinquish control of the$
variable (or even thejQuery
variable if you passtrue
as a param to it --- but this is NOT a best practice). UsingjQuery.noConflict()
can be very helpful in Visualforce page development when you don't know how other components that you'll be using within the page will be making use of external JS libraries --- other JS libraries might use the$
variable to refer, for instance, to an old version of jQuery, or to some entirely different JS library altogether. So using something likevar $j = jQuery.noConflict()
, or even a namespaced version likeacme.$ = jQuery.noConflict()
, allows you to rest easy knowing that all calls to$j
(depending on the scope of where you use it, of course) will return references tojQuery
as you expect them to, and NOT to some other vendor's code or version of jQuery.