Working with JavaScript and jQuery | Drupal.org
original source : https://www.drupal.org/node/171213
Working with JavaScript and jQuery
Last updated October 24, 2014. Created on August 28, 2007.
Edited by camorim, rovo, williamdelvalle, Pere Orga. Log in to edit this page.
Using JavaScript adds dynamic presentation effects to a theme. In addition to custom JavaScript files many Drupal developers find jQuery useful. jQuery is a lightweight JavaScript library which is built into Drupal. jQuery contains all the common DOM, event, effects, and Ajax functions.
Drupal 7 includes jQuery 1.4.4 and jQuery UI 1.8.7. Drupal 6.0 to 6.2 included jQuery 1.2.3 while Drupal 6.3 includes an update to jQuery 1.2.6. For use in module development which requires a later version of jQuery, apply the jQuery update module. When JavaScript is added to a page through Drupal, jQuery is automatically added to the page.
More comprehensive information on the JavaScript APIs and the use of JavaScript in Drupal can be found in the Developer Guide.
For more information about jQuery visit the jQuery API and Documentation site.
Drupalize.Me offers a free, 11-minute video introduction to using jQuery in Drupal 6&7…
Intro to jQuery in Drupal
Adding JavaScript
There are two ways for Themes to easily add JavaScript to a page.
In .info File
JavaScript files can be added to a theme’s .info file using the scripts tag. For example, to add the script foo.js to every page on a Drupal site add the following to the theme’s .info file.
scripts[] = foo.js
Clear the theme cache for this change to take effect
Scripts added in a theme’s .info file are added at the theme level of ordering and will come after core/library JavaScript and module JavaScript. This ordering is important because it allows the theme JavaScript an opportunity to act on the page after the JavaScript providing the functionality within the page.
In Drupal 6 there is a default script file, named script.js that can be added to a theme without specifying it in the .info file. If that script is included in the theme it will be automatically added to all pages. In Drupal 7 all script files need to be specified.
In template.php
Alternately, scripts can be added in the template.php file using drupal_add_js() or, in Drupal 7,drupal_add_library(). For example, adding a script in the root directory of a theme named foo.js would go like:
In Drupal 6:
<?php
function example_preprocess_page(&$variables) {
drupal_add_js(drupal_get_path('theme', 'example'). '/foo.js', 'theme');
// We need to rebuild the scripts variable with the new script included.
$variables['scripts'] = drupal_get_js();
}
?>
In Drupal 7:
<?php
function example_preprocess_html(&$variables) {
$options = array(
'group' => JS_THEME,
);
drupal_add_js(drupal_get_path('theme', 'example'). '/foo.js', $options);
}
?>
Note, in Drupal 7 the $scripts variable does not need to be rebuilt. $scripts is built intemplate_process_html which happens after this function.
Drupal 7 includes library management. Libraries are collections of JavaScript, CSS, and dependent libraries. For example, Drupal 7 includes jQuery UI. jQuery UI is a component library with internal dependencies. When ui.autocomplete is included it needs ui.core and ui.position to be included as well. Drupal libraries takes care of this for us. Adding ui.autocomplete with all of it’s CSS, JS, and dependencies can be accomplished with the following code:
<?php
drupal_add_library('system', 'ui.autocomplete');
?>
This one command includes jquery.ui.autocomplete.js, jquery.ui.autocomplete.css, and the dependencies of jquery.ui.position.js, jquery.ui.widget.js, jquery.ui.core.js, jquery.ui.core.css, and jquery.ui.theme.css. For more information on drupal_add_library see the API documentation.
JavaScript closures
It’s best practice to wrap your code in a closure. A closure is nothing more than a function that helps limit the scope of variables so you don’t accidentally overwrite global variables.
// Define a new function.
(function () {
// Variables defined in here will not affect the global scope.
var window = "Whoops, at least I only broke my code.";
console.log(window);
// The extra set of parenthesis here says run the function we just defined.
}());
// Our wacky code inside the closure doesn't affect everyone else.
console.log(window);
A closure can have one other benefit, if we pass jQuery
in as a parameter we can map it to the $
shortcut allowing us to use use $()
without worrying if jQuery.noConflict()
has been called.
// We define a function that takes one parameter named $.
(function ($) {
// Use jQuery with the shortcut:
console.log($.browser);
// Here we immediately call the function with jQuery as the parameter.
}(jQuery));
Note that there are two acceptable syntaxes for closures: the parenthesis that closes the first parenthesis can come either before or after the (jQuery)
.
The .ready() function also has the ability to alias the jQuery object:
jQuery(document).ready(function($) {
// Code that uses jQuery's $ can follow here.
});
In Drupal 7 jQuery.noConflict()
is called to make it easier to use other JS libraries, so you’ll either have to type out jQuery()
or have the closure rename it for you. More examples can be found onjQuery’s api site.
JavaScript behaviors / JavaScript on AJAX forms
Drupal uses a “behaviors” system to provide a single mechanism for attaching JavaScript functionality to elements on a page. The benefit of having a single place for the behaviors is that they can be applied consistently when the page is first loaded and then when new content is added during AHAH/AJAX requests. In Drupal 7 behaviors have two functions, one called when content is added to the page and the other called when it is removed.
Behaviors are registered by setting them as properties of Drupal.behaviors
. Drupal will call each and pass in a DOM element as the first parameter (in Drupal 7 a settings object will be passed as the second parameter). For the sake of efficiency the behavior function should do two things:
- Limit the scope of searches to the context element and its children. This is done by passing context parameter along to jQuery:
jQuery('.foo', context);
- Avoid processing the same element multiple times.
In Drupal 6 assign a marker class to the element and use that class to restrict selectors:jQuery('.foo:not(.foo-processed)', context).addClass('foo-processed').css('color', 'red');
In Drupal 7 use the jQuery Once plugin that’s bundled with core:jQuery('.foo', context).once('foo').css('color', 'red');
As a simple example lets look at how you’d go about finding all the https
links on a page and adding some additional text marking them as secure, turning <a href="https://example.com">Example</a>
into <a href="https://example.com">Example (Secure!)</a>
. This should make the importance of only running the code once apparent, if our code ran twice the link would end up reading “Example (Secure!) (Secure!)”.
In Drupal 6 it would be done like this:
// Using the closure to map jQuery to $.
(function ($) {
// Store our function as a property of Drupal.behaviors.
Drupal.behaviors.myModuleSecureLink = function (context) {
// Find all the secure links inside context that do not have our processed
// class.
$('a[href^="https://"]:not(.secureLink-processed)', context)
// Add the class to any matched elements so we avoid them in the future.
.addClass('secureLink-processed')
// Then stick some text into the link denoting it as secure.
.append(' (Secure!)');
};
// You could add additional behaviors here.
Drupal.behaviors.myModuleMagic = function(context) {};
}(jQuery));
In Drupal 7 it’s a little different because behaviors can be attached when content is added to the page and detached when it is removed:
// Using the closure to map jQuery to $.
(function ($) {
// Store our function as a property of Drupal.behaviors.
Drupal.behaviors.myModuleSecureLink = {
attach: function (context, settings) {
// Find all the secure links inside context that do not have our processed
// class.
$('a[href^="https://"]', context)
// Only process elements once.
.once('secureLink')
// Then stick some text into the link denoting it as secure.
.append(' (Secure!)');
}
};
// You could add additional behaviors here.
Drupal.behaviors.myModuleMagic = {
attach: function (context, settings) { },
detach: function (context, settings) { }
};
}(jQuery));
JavaScript on your AJAX form
Attach jQuery to Drupal.behaviors, that way it can be run anytime new DOM elements are inserted. One example, if you’re using AJAX in Views, each time a section of the page reloads, it will reload/run jQuery.
Here’s how to do it!
- Create a new file in your theme directory(i.e. /sites/all/themes/[mytheme]/), called script.js
- Insert this into your theme .info file(i.e. /sites/all/themes/[mytheme]/[mytheme].info):
scripts[] = script.js - Insert the following into script.js (the file you created in step 1):
(function($) {
Drupal.behaviors.myBehavior = {
attach: function (context, settings) {
//code starts
$("body").click(function() {
alert("Hello World");
});
//code ends
}
};
})(jQuery);
Clicking anywhere on your website, now alerts – Hello World.
JavaScript theming
Drupal provides a theming mechanism for JavaScript code in a similar manner to the way theming works within the rest of Drupal. This enables themes to customize the markup generated by JavaScript.
Modules provide theme functions for their markup. For example, the following code uses the theme function powered
(This displays a “powered by Drupal” icon):
Drupal.theme.prototype.powered = function(color, height, width) {
return '<img src="/misc/powered-'+ color +'-'+ height +'x'+ width +'.png" />';
}
When a module wants to insert the markup it would do so in a matter like:
$('.footer').append(Drupal.theme('powered', 'black', 135, 42));
This will place an image in any elements with the class footer with the following markup:
<img src="http://drupal.org/misc/powered-black-135x42.png" />
When a theme wants to provide a different markup it can do so by providing an alternate theme function. Following our example the following function provides an a theme function for the theme.
Drupal.theme.powered = function(color, height, width) {
return '
';
}
While the modules theme function is at Drupal.theme.prototype.powered
the theme’s is at Drupal.theme.powered
. Including this function in the themes JavaScript will cause the markup generated by the snippet:
$('.footer').append(Drupal.theme('powered', 'black', 135, 42));
to be:
JavaScript theme functions are entirely free in their return value. They can vary from simple strings to complex data types like objects, arrays, and jQuery elements. Refer to the original (default) theme function to see what your custom theme function should return.
Cross reference to related community documentation (Drupal.org “Developer Guide” as well as “Theming Guide”):
- Developer Guide – For more information on using JavaScript and jQuery in Drupal, see theJavaScript section of the developer guide. Also, join the JavaScript group on Groups.Drupal.org to get advice on JavaScript and jQuery:http://groups.drupal.org/javascript
- Theming Guide – Working with JavaScript and jQuery for links to two buildamodule.com tutorial videos
JQuery Theming Tips for Drupal 7
original source : http://highrockmedia.com/blog/jquery-theming-tips-drupal-7
JQuery Theming Tips for Drupal 7
I often see posts on the drupal.org forums and elsewhere in regard to implementing jQuery scripts and code into Drupal. It seems common that users try to attach JQuery right within page.tpl.php or html.tpl.php. In other words, it’s hard-coding a script into a page and it’s not ideal. Some try to render it using the PHP filter within a block or node. The disadvantages of these methods are that code added like this cannot be included in any caching or aggregation methods and can also cause conflicts that would be tricky to troubleshoot. For best Drupal theming practices, I have outlined some methods below.
A Few Methods
There are a few methods that work well for adding additional custom JQuery scripts to Drupal 7 and some of this depends on the use case. Do you have some general code that will be used sitewide or do you have specific code that just needs to be added to the home page or a specific content type for example? Here are the two most common ways:
drupal_add_js
This method is good for one-offs such as adding code to specific pages and not the entire site. Use the drupal_add_js method by adding code to your theme’s template.php file. In the snippet below, we test to see if it’s the drupal home page and then if it is, add the code.
function my_theme_preprocess_html(&$variables) { if (drupal_is_front_page()) { drupal_add_js(drupal_get_path('theme', 'my_theme') . '/js/my_script.js'); } }
In the above code sample, you would replace ‘my_theme’ with the actual machine name of your theme. ‘js’ is a folder within your theme folder that contains your script(s). We can also use the drupal_add_js method to a specific content type like this:
function my_theme_preprocess_node(&$variables) { if (isset($variables['node']) && $variables['node']->type == 'page') { // Add js drupal_add_js(drupal_get_path('theme', 'my_theme') . '/js/scripts.js'); $variables['scripts'] = drupal_get_js(); } }
function my_theme_preprocess_node(&$variables) { if(arg(0) == 'node' && arg(1) == '8' && arg(3) == null) { drupal_add_js(drupal_get_path('theme', 'my_theme') . '/js/custom.js'); } }
Theme .info file
scripts[] = js/custom.js
The Code
So now you are all set adding your script but how do you format JQuery calls for Drupal 7? A lot has changed with the way in which JQuery is called in Drupal 7. In Drupal 6, we used to do something like this:
Drupal.behaviors.myfunction = function(context) { //some jquery goodness here... };
However, now in Drupal 7, it would look like this:
(function ($) { //add drupal 7 code Drupal.behaviors.myfunction = { attach: function(context, settings) { //end drupal calls //some jquery goodness here... }}}) (jQuery);
Ajax?
One addtional hint is if you need to execute some JQuery where there is an Ajax event, you need to make JQuery aware of that. You can do that with an event handler for Ajax:
(function ($) { //add drupal 7 code Drupal.behaviors.MyfunctionTheme = { attach: function(context, settings) { //end drupal 7 calls //Tell JQuery that there's an Ajax event first $('.mydiv').ajaxComplete(function() { // now your actual code $(this).remove() // or whatever code you need to execute }); }}}) (jQuery);
Note that I have used and tested all these methods in various sites I have designed, developed and themed. Let me know in the comments if you have any additional tips that I might have missed. Happy Drupal JQuery-ing!
JQuery Theming Tips for Drupal 7
I often see posts on the drupal.org forums and elsewhere in regard to implementing jQuery scripts and code into Drupal. It seems common that users try to attach JQuery right within page.tpl.php or html.tpl.php. In other words, it’s hard-coding a script into a page and it’s not ideal. Some try to render it using the PHP filter within a block or node. The disadvantages of these methods are that code added like this cannot be included in any caching or aggregation methods and can also cause conflicts that would be tricky to troubleshoot. For best Drupal theming practices, I have outlined some methods below.
A Few Methods
There are a few methods that work well for adding additional custom JQuery scripts to Drupal 7 and some of this depends on the use case. Do you have some general code that will be used sitewide or do you have specific code that just needs to be added to the home page or a specific content type for example? Here are the two most common ways:
drupal_add_js
This method is good for one-offs such as adding code to specific pages and not the entire site. Use the drupal_add_js method by adding code to your theme’s template.php file. In the snippet below, we test to see if it’s the drupal home page and then if it is, add the code.
function my_theme_preprocess_html(&$variables) { if (drupal_is_front_page()) { drupal_add_js(drupal_get_path('theme', 'my_theme') . '/js/my_script.js'); } }
In the above code sample, you would replace ‘my_theme’ with the actual machine name of your theme. ‘js’ is a folder within your theme folder that contains your script(s). We can also use the drupal_add_js method to a specific content type like this:
function my_theme_preprocess_node(&$variables) { if (isset($variables['node']) && $variables['node']->type == 'page') { // Add js drupal_add_js(drupal_get_path('theme', 'my_theme') . '/js/scripts.js'); $variables['scripts'] = drupal_get_js(); } }
function my_theme_preprocess_node(&$variables) { if(arg(0) == 'node' && arg(1) == '8' && arg(3) == null) { drupal_add_js(drupal_get_path('theme', 'my_theme') . '/js/custom.js'); } }
Theme .info file
scripts[] = js/custom.js
The Code
So now you are all set adding your script but how do you format JQuery calls for Drupal 7? A lot has changed with the way in which JQuery is called in Drupal 7. In Drupal 6, we used to do something like this:
Drupal.behaviors.myfunction = function(context) { //some jquery goodness here... };
However, now in Drupal 7, it would look like this:
(function ($) { //add drupal 7 code Drupal.behaviors.myfunction = { attach: function(context, settings) { //end drupal calls //some jquery goodness here... }}}) (jQuery);
Ajax?
One addtional hint is if you need to execute some JQuery where there is an Ajax event, you need to make JQuery aware of that. You can do that with an event handler for Ajax:
(function ($) { //add drupal 7 code Drupal.behaviors.MyfunctionTheme = { attach: function(context, settings) { //end drupal 7 calls //Tell JQuery that there's an Ajax event first $('.mydiv').ajaxComplete(function() { // now your actual code $(this).remove() // or whatever code you need to execute }); }}}) (jQuery);
Note that I have used and tested all these methods in various sites I have designed, developed and themed. Let me know in the comments if you have any additional tips that I might have missed. Happy Drupal JQuery-ing!