Cloudkiller
Cloudkiller

Reputation: 1636

jquery.fn getting overwritten

In my site I have a jquery function created by using the jQuery.fn method like so:

jQuery.fn.equalHeights = function() {
    var currentTallest = 0;
    jQuery(this).each(function(){
        if (jQuery(this).height() > currentTallest) {
            currentTallest = jQuery(this).height();
        }
    });
    jQuery(this).css('min-height', currentTallest);
};

I use this function to equalize the size of sidebars on my site so I call it after the page has finished loading to make sure everything is in place before I do the sizing.

jQuery(window).load(function(){
    jQuery('#sidebar-one, #sidebar-two, #content').equalHeights();
});

This works perfectly except for on some of my pages users will add another instance of the jQuery library to their page in the body area (for whatever reason). This second library causes my function to stop working properly. I'm assuming this is because the second jQuery overwrites any functions created with the jQuery.fn method. Is there any way to prevent that from happening?

Notes: My site is running Drupal 7 so I can't easily move the scripts to the bottom of the page. The equalHeights function was not written by me; I believe I found it here on stack so my knowledge of the fn method (and JS in general) is not that extensive.



EDIT: Based on all the great suggestions below, this is how I finally got it to work.

First, I give my "default" instance of jQuery a new variable to reference:

var JQ = jQuery.noConflict();

Second, I call the more efficient version of the equalHeights function using the new jQuery variable:

JQ.fn.equalHeights = function() {
    var tallest = 0;
    return this.each(function(){
        var h = JQ(this).height();
        tallest = h > tallest ? h : tallest;
    }).css("minHeight", tallest);
};

Third, I call my function using the new jQuery variable:

JQ('#sidebar-one, #sidebar-two, #content').equalHeights();

So now any time I need to reference my original jQuery library I just use JQ and I don't have to worry about another library stepping on any of my functions.

I realize this isn't the best way to fix this problem and I'm going to work on eliminating the additional jQuery libraries but this will at least keep my sidebars properly sized in the mean time.

Upvotes: 2

Views: 848

Answers (3)

mekwall
mekwall

Reputation: 28974

This is because the second version of jQuery will overwrite the previous one. Unless you are using a legacy library that isn't compatible with later versions of jQuery, there's no reason to load two different versions.

To use a later version of jQuery with Drupal 7 you need to use the hook_js_alter script and then add something like the following to your Drupal theme (courtesy of oldwildissue):

function MYTHEME_js_alter(&$javascript) {
  //We define the path of our new jquery core file
  //assuming we are using the minified version 1.8.3
  $jquery_path = drupal_get_path('theme','MYTHEME') . '/js/jquery-1.8.3.min.js';

  //We duplicate the important information from the Drupal one
  $javascript[$jquery_path] = $javascript['misc/jquery.js'];
  //..and we update the information that we care about
  $javascript[$jquery_path]['version'] = '1.8.3';
  $javascript[$jquery_path]['data'] = $jquery_path;

  //Then we remove the Drupal core version
  unset($javascript['misc/jquery.js']);
}

This will allow you to use any version of jQuery with Drupal 7.

I also noticed that your plugin is using some pretty bad practices. Here's an optimized version of your plugin, using good and well established practices:

(function($){
    $.fn.equalHeights = function() {
        var tallest = 0;
        return this.each(function(){
            var h = $(this).height();
            tallest = h > tallest ? h : tallest;
        }).css("minHeight", tallest);
    };
}(jQuery));

Upvotes: 1

Bergi
Bergi

Reputation: 664548

Wrap your snippet in a module IEFE, passing the "old" jQuery reference:

(function($) {
    // $ will always point to the jQuery version with the `equalHeights` method
    $(window).load(function(){
        $('#sidebar-one, #sidebar-two, #content').equalHeights();
    });
}(jQuery));

See also jQuery.noConflict for further tricks.

Upvotes: 1

MDEV
MDEV

Reputation: 10838

You could technically copy jQuery to a new variable just for your use - i.e. JQ = jQuery; then do JQ(this)...

Though you may just want to address the insertion of subsequent versions - stopping it, or ensuring your version is added last and all of your code is executed afterwards so they can't override it

Upvotes: 1

Related Questions