[SalesForce] Use of (BlockUI) plugin in jquery constantly breaks Visualforce pages

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:

  1. Have embedded Javascript
  2. Include external Javascript
  3. 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 of jQuery.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 use j$ = 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 the jQuery global object by, essentially, registering jQuery.fn.block = function(){}, jQuery.fn.unblock = function(){}, etc. However, this code attaches/registers its plugin within a CLOSURE, so its reference to the jQuery 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:

if (!jQuery.fn.block) {
    // Load the block UI plugin
} else {
   // Hurray, it's already loaded!
}

Finally, as an aside, all that jQuery.noConflict() does is to relinquish control of the $ variable (or even the jQuery variable if you pass true as a param to it --- but this is NOT a best practice). Using jQuery.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 like var $j = jQuery.noConflict(), or even a namespaced version like acme.$ = 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 to jQuery as you expect them to, and NOT to some other vendor's code or version of jQuery.

Related Topic