Add Awesome Elements to Drupal with jQuery

image

 

Drupal 7 comes packed with functionality but what do you do when you want to implement some of those incredible visual elements that you see across the web? Cover flow like image galleries, fade animations, sliding page elements, smooth scrolling and other dynamic presentation effects can help push your site design to a whole other level.

Fortunately, Drupal 7 comes loaded with an answer in jQuery. jQuery is a lightweight JavaScript library which contains many common DOM, event, effects, and Ajax functions. While Drupal 7 ships with jQuery 1.4.4. update, if you want to add effects not found in that library, for example components from jQuery UI, you'll need to add the extra script yourself.

 Adding jQuery Extras

When you add new JavaScript files to Drupal, you'll need to tell Drupal where to find them. There are several options but perhaps the simplest is to add a line to your theme's .info file. For example, if you have a JavaScript folder in your theme folder with a JavaScript file named myCustomScript.js, you would add the line:

scripts[] = 'js/myCustomScript.js'

Note that loading the file in this way will make the JavaScript load on every page of your site. Another method which will give you more options is to add your JavaScript via your theme's template.php file using the preprocess html function. For example, if your theme is named myCustomTheme you would use the function:

function myCustomTheme_preprocess_html(&$variables) {
  drupal_add_js(drupal_get_path('theme', 'myCustomTheme'). 'js/myCustomScript.js');
}

When loading JavaScript via the template.php file you can optionally load the file for a specific page. For instance, if you only want the JavaScript on your site's home page:

function myCustomTheme_preprocess_html(&$variables) {
  if (drupal_is_front_page()) {
    drupal_add_js(drupal_get_path('theme', 'myCustomTheme'). 'js/myCustomScript.js');
  }
}

You can also use the function drupal_add_library() instead of drupal_add_js(). As noted on Drupal.org, Working with JavaScript and jQuery, Drupal 7 includes library management. For example, to load the jQuery UI autocomplete library, including all dependencies, use:

drupal_add_library('system', 'ui.autocomplete');

Check out Working with JavaScript and jQuery for other available options such as the script type and scope.

JavaScript Behaviors

You may run into issues when you are using JavaScript on pages that have AJAX loaded content. For example, you may have a view that loads content via AJAX. If you have custom JavaScript that should be acting on these elements, it won't work since the JavaScript attaches on page load. To avoid this, load your JavaScript using a Drupal behavior function, for example:

(function ($) {
Drupal.behaviors.exampleModule = {
  attach: function (context, settings) {
        $('.example', context).click(function () {
        $(this).next('ul').toggle('show');
      });
    }
  };
})(jQuery);

This helps because when new content is added to a page, e.g. in a view, all behaviors are called again. In this example, you will also notice that the function is wrapped in "function($) {...})(jQuery);. This allows the use of the jQuery shorthand $ within the function. This is needed since many frameworks other than jQuery use $.

Use Cases

Ok, enough background, let's look at some awesome use cases! Some common use cases involve animation like animating image fill, animating hover effects or full screen sliders. The coolest jQuery enhancement that I've implemented recently involved improving the look and feel of the default numerical view filter. Thanks to Drupal.org user, nagiek for the script I based this on.

Let's say you have a view with a bunch of filters. One or more of these may accept numerical values while others may be check boxes. The user can easily click any of the check boxes but has to resort to the keyboard to enter the numerical values. Even worse, there may be a limited range of acceptable numbers. We can improve the user experience, not to mention the visual appeal, by replacing the bland text box with a jQuery slider.

I assume you know how to add a filter to your view and how to expose the filter to visitors, allowing them to change it. With that set up, you have the view with a text box.  With the addition of a single JavaScript file and some CSS, you can swap that out for a slider. The following script locates the text based numerical filter, hides it from the end user and inserts a slider into the DOM.

Drupal.behaviors.customSlider = {
attach: function() {
// NOTE: the exposed filter was given a filter identifier of "slider-filter". Views adds the "edit-" and "-min" part.
var min = $("input#edit-slider-filter");
if (!min.length) {
// No min/max elements on this page
return;
}
// Set default values or use those passed into the form
var init_min = ('' == min.val()) ? 0 : min.val();

// Set initial values of the slider
min.val(init_min)
// Insert the slider before the min/max input elements, unless it exists already
if($('.ui-slider').length == 0) {
min.parents('div.views-widget').before(
$('<div></div>').slider({
values: [init_min],
step: 20,
change:function() { $("#edit-submit-startup-tools-list").click(); },
slide: function(event, ui){
// Update the form input elements with the new values when the slider moves
min.val(ui.values[0]).hide();
}
})
); // Added .hide() before the ';' to remove the input elements altogether.
} //end if

}
};
})(jQuery);

Since I have AJAX enabled on this view, I check to see if the slider has already been inserted into the page prior to adding it again, "if($('.ui-slider').length == 0)". Also, in the case of this view, the value is stored in Drupal in increments of 20, from 0 to 100, so I instantiated the slider to also increment by 20s, "step: 20,".

As a further enhancement, I added a simple conversion so the slider exposes values from 1 to 5. I have the script inserting a label after the slider with the text of the current converted filter value.

Here is the script with the label inserted:

Drupal.behaviors.customSlider = {
  attach: function() {
  // NOTE: the exposed filter was given a filter identifier of "slider-filter". Views adds the "edit-" and "-min" part.
  var min = $("input#edit-slider-filter");
  if (!min.length) {
    // No min/max elements on this page
    return;
  }
  // Set default values or use those passed into the form
  var init_min = ('' == min.val()) ? 0 : min.val();
  var init_star = 0;
  var star_class = 'onestar';
  if(init_min > 0)
  {
    init_star = init_min/20;
  }

  // Set initial values of the slider
  min.val(init_min)
  // Insert the slider before the min/max input elements, unless it exists already
  if($('.ui-slider').length == 0) {
    min.parents('div.views-widget').before(
    $('<div></div>').slider({
      values: [init_min],
      step: 20,
      change:function() { $("#edit-submit-startup-tools-list").click(); },
      slide: function(event, ui){
        // Update the form input elements with the new values when the slider moves
        min.val(ui.values[0]).hide();
      }
      })
      ); // Added .hide() before the ';' to remove the input elements altogether.
    } //end if

    if(($('.ui-slider').length > 0) && ($('#ui-slider-lbltxt').length ==0)) {
      switch (init_star) {
        case 1: star_class = 'onestar';
        break;
        case 2: star_class = 'twostar';
        break;
        case 3: star_class = 'threestar';
        break;
        case 4: star_class = 'fourstar';
        break;
        case 5: star_class = 'fivestar';
        break;
      }

        min.parents('div.views-widget').before(
         "<span id='ui-slider-lbltxt' class='" + star_class + "'>" + init_star + " Star</span>"
        );
      } //end if

     }
    };
  })(jQuery);

This script demonstrates how easy it is to substitute basic page elements with fantastic jQuery alternatives. Drop me a line with questions or comments.

 

Subscribe to Our Newsletter

Stay In Touch