Last updated February 7, 2012. Created by katbailey on March 29, 2010.
Edited by arnoldbird, sillygwailo, e-anima, gagarine. Log in to edit this page.
Drupal 7 has introduced several new techniques that allow you far greater flexibility and control in the scripts you can have on your Drupal site's pages.
Weighted JavaScript
drupal_add_js() now allows you to add a weight value to each script you’re adding so you can completely control the order in which the script tags appear:
- JS_LIBRARY: Any libraries, settings, or jQuery plugins.
- JS_DEFAULT: Any module-layer JavaScript.
- JS_THEME: Any theme-layer JavaScript
Example:
drupal_add_js('jQuery(document).ready(function () { alert("Hello!"); });', array('type' => 'inline', 'scope' => 'footer', 'weight' => 5));Adding JavaScript in the module's .info file
You can now add Javascript in the module's .info file if it should be added on every page. This allows Javascript to be aggregated in an optimal way, and is the preferred method of adding Javascript that most visitors will need on a typical site visit:
scripts[] = somescript.jsExternal JavaScript
drupal_add_js() now allows you to add external scripts.
Example:
drupal_add_js('http://example.com/example.js', 'external');Overriding JavaScript
hook_js_alter() allows you to modify the path referenced by one of the scripts added by core or another module. An obvious example is if you want to use a newer version of jQuery than what comes with core:
function hook_js_alter(&$javascript) {
$javascript['misc/jquery.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js'; // Swap out jQuery to use an updated version of the library
}JavaScript Libraries
There is now a standard way of adding collections of JavaScript and CSS, such as jQuery plugins. If you have a set of JavaScript and/or CSS that could be considered a package, provide it as a library to other modules by implementing hook_library(), and include it it in your own pages either by using #attached['library'] or drupal_add_library(). This is the preferred way to deal with JavaScript and CSS which might be used by other modules.
Modules define libraries which can be added when needed. For example, system.module defines the Vertical Tabs library, which includes one js file and one css file:
function system_library() {
...
// Vertical Tabs.
$libraries['vertical-tabs'] = array(
'title' => 'Vertical Tabs',
'website' => 'http://drupal.org/node/323112',
'version' => '1.0',
'js' => array(
'misc/vertical-tabs.js' => array(),
),
'css' => array(
'misc/vertical-tabs.css' => array(),
),
);
...
return $libraries;
}The library gets added when it's needed, through a call to drupal_add_library:
function theme_vertical_tabs($variables) {
$element = $variables['element'];
// Add required JavaScript and Stylesheet.
drupal_add_library('system', 'vertical-tabs');
return '<div class="vertical-tabs-panes">' . $element['#children'] . '</div>';
}Prefer drupal_add_library() and always use it for core JavaScript files
drupal_add_js() should not be used for JavaScript which is already included in a library (as all core JavaScript libraries are). Use drupal_add_library() instead.
Using jQuery
jQuery is now namespaced to avoid conflicts with other Javascript libraries such as Prototype. All your code that expects to use jQuery as $ should be wrapped in an outer context like so.
(function ($) {
// All your code here
})(jQuery);If you don't, you may see the error
Uncaught TypeError: Property '$' of object [object DOMWindow] is not a function or similar.
Behaviors
Behavior handling has changed again in Drupal 7, with modules now required to explicitly define their attach handler, and optionally specify a detach handler.
Instead of the settings being a global object, settings are now passed to your handlers directly, after the context.
These changes, besides namespaced jQuery, mean basic module code should go from something like this in Drupal 6:
Drupal.behaviors.exampleModule = function (context) {
$('.example', context).click(function () {
$(this).next('ul').toggle('show');
});
}To something like this in Drupal 7:
(function ($) {
Drupal.behaviors.exampleModule = {
attach: function (context, settings) {
$('.example', context).click(function () {
$(this).next('ul').toggle('show');
});
}
};
})(jQuery);jQuery Once method for applying JavaScript behaviors once
When applying certain behaviours to elements through JavaScript, we apply a class to the element to depict whether or not the effect has been applied.
Using jQuery Once (integrate in D7), the developer experience of applying these effects is improved. Note that there is also the removeOnce method that will only take effect on elements that have already applied the behaviors.
Drupal.behaviors.mybehavior = {
attach: function (context, settings) {
$('input.mybehavior', context).once('mybehavior', function () {
// Apply the MyBehaviour effect to the elements only once.
});
}
};For best-practice examples, it's helpful to look at (comparatively) simple examples such as misc/collapse.js to see how it's done.
Comments
settings
The settings object behaves similarly to Drupal 6 with the exception that it is not within the Drupal namespace.
So "Drupal.settings.blah.setting" becomes "settings.blah.setting".
I solved part of this in
I solved part of this in trying to convert from a Drupal 6 theme to Drupal 7. I have a nice little JQuery drop down menu function that no longer worked in Drupal 7.
My old Drupal 6 code was:
Drupal.behaviors.MyThemeBehavior = function(context) {
jQuery('#navigation ul').superfish({
animation: { opacity: 'show', height:'show' },
easing: 'swing',
speed: 250,
autoArrows: false,
dropShadows: false /* Needed for IE */
});
};
Now in Drupal 7, based on the code sample on this page, I did this:
(function ($) {
Drupal.behaviors.MyTheme = {
attach: function(context, settings) {
$('#navigation ul', context).superfish(function () {
});
}
};
})(jQuery);
The only thing I can't figure out how to do it put the animation, easing and speed code back in but at least the menus are working to a degree.
Update
Finally found a fix to this:
(function ($) {
Drupal.behaviors.naturalessenceTheme = {
attach: function(context, settings) {
$('#navigation ul', context).superfish({
animation: { opacity: 'show', height:'show' },
speed: 250,
autoArrows: false,
dropShadows: false /* Needed for IE */
});
}
};
})(jQuery);
High Rock Media | Drupal Photography | Skype: highrockmedia | Twitter
more please.....
I found this page very helpful but am still having trouble getting jQuery to work in D7. I'm not a programmer but I can get around html and CSS well enough. I've used Drupal for a few years now, am comfortable manipulating themes although I bawk at writing my own modules. A few questions please.
I've downloaded the jq4dat theme, the template.php file uses drupal_add_library in the preprocess_page function. I've added another one (for tabs) and the javascript and css from misc/ui is now included in the html source. I've updated the .info and my script (from http://flowplayer.org/tools/demos/tabs/index.html), appropriately wrapped is also being called. It looks like this..
(function ($) {
$("ul.tabs").tabs("div.panes > div");
})(jQuery);
I've also added the CSS as described at the flowplayer site and included the html in my node content.
Do I need any drupal behaviours? Is my script OK? Something is missing.
I'd love to get this happening and would be happy to help with the documentation once I know how to work it.
Thanks
working example for ui.tabs
I finally found a working example here
http://www.jromero.me/blog/jquery-ui-drupal
hope it helps with your problem as well
Clariification on drupal.add.js in Drupal 7
Sorry if this is a totally dumb question but can someone explain where the drupal.add.js needs to be inserted. Is it in template.php or what?
I have been playing with the Bluemasters theme and it includes a script on the front page by incorrectly adding the script at the top of the page--front.tpl.php. It works but the source code ends up with two body tags. Erk! I could copy html.tpl.php and add the script there but there has to be a better way. I have also tried adding the scripts [] = js/bluemasters.js entry to the .info file but this doesn't seem to include anything.
Any suggestions?
Partially resolved
I figured out to put the drupal_add_js at the top of page--front.tpl.php. That works fine. Still can't work out how to include script via .info file though.
drupal_add_js() can go in
drupal_add_js() can go in template files and even in php fields in content, anywhere that php is evaluated. That said, it's best/neatest to put them in a function (usually preprocess) in your template.php, or in a module if that's what is providing the content that needs the javascript.
An example of a preprocess function would be something like this:
<?php
//This is preprocessing the html on a theme named "my_theme", checking if a particular class is applied to the body, and adding js if it is.
function my_theme_preprocess_html(&$variables) {
//Checks if the required string is in the classes array. Here I'm looking for page-my-view, which is the class that appears in the body tag on pages created by a view called My View.
if ((in_array('page-my-view', $variables['classes_array']))) {
//Set up the options for the drupal_add_js() function See the api docs for explanation.
$options = array(
'group' => JS_LIBRARY,
'type' => 'external'
);
//here's the function itself.
drupal_add_js('http://ajax.microsoft.com/ajax/jquery.cycle/2.88/jquery.cycle.min.js', $options);
//Add another js file. First I'll make some changes to the $options (tell Drupal it's an internal file). I want to keep the type as JS_LIBRARY, so I leave it as defined above.
$options = array(
'type' => 'file'
);
//..and use the function again.
drupal_add_js(drupal_get_path('theme', 'my_theme'). '/js/script.js', $options);
}
}
?>
That would give me two files, http://ajax.microsoft.com/ajax/jquery.cycle/2.88/jquery.cycle.min.js and sites/all/my_theme/js/script.js, added only to pages where the body class contains "page-my-view". You might use similar code to preprocess your node and add js based on node type, or check a field value and add js accordingly.
This link can help
http://drupal.org/node/520616
I'd like to see some
I'd like to see some explanation around jquery.once.js plugin. All of the core Javascript that I've looked at so far makes use of this plugin. I'd like to see an explanation from someone in the know as to why this is used everywhere and what it replaces from Drupal 6.
I'll take a swing at an explanation here, I'd love to hear comments. In my own experimentation I gather that its a way to ensure that you only run JS code on a set of matched elements once, hence the plugins name. The plugin works by removing elements from the matched set with a class that labels the element as having been previously processed. jQuery each() is run on the remaining elements passing in the function that was passed as the second argument to jQuery once(). Thus, introducing jquery.once.js into core gives us a standardized was to ensure that our Drupal behaviors are not run more than once on a set of matched elements, which could for example set the same click handler twice.
Matt
I add some text about that in
I add some text about that in the doc.. You can also check http://drupal.org/node/224333#jquery_once
That's great thanks!
That's great thanks!
behaviors
Hi,
i have a working code for views exposed filter. when submit button is clicked its not reloade. but the code submits the form without ajax. i have read that behaviors should help with that but not working.
Am i missing something?
(function($){
Drupal.behaviors.dl = {
attach: function(context, settings) {
$(".picture-submit", context).click(function() {
$("#views-exposed-form-media-updates-list-page-media-updates").submit();
});
}
};
})(jQuery);
I can't get a body.ready event to fire
Detailed description of the problem here: http://drupal.stackexchange.com/questions/4401/how-do-get-a-body-onload-... , includes all the details of how I built the module, which is just a JavaScript file.
Basically, I see my .js file loaded on the page (there's a script tag when I View Source), but the attach() I defined doesn't seem to do anything. I tried adding a $(body).ready() to a Drupal.behavior as described above to do what I need, but it never fires. The StackExchange entry above has links to the source.
I want to implement this
I want to implement this sticky-scroll jquery plug-in on a drupal 7 theme to both sidebars.
https://github.com/Forrst/sap/blob/master/README.md
I have no idea where/how to do #3. I'm think it has something to do with Drupal.behaviors.??
I'm comfortable with drupal theming using css but new to jquery.
Help!
In the .js that you're
In the .js that you're calling with you info file, attach anything you'd normally put in a document.ready() to Drupal behaviors. Example:
(function ($) {
Drupal.behaviors.naturalessenceTheme = {
attach: function(context, settings) {
/*Add your js code here*/
}
};
})(jQuery);
Adding JavaScript in the module's .info file
Does this mean that a js file added in an .info file is actually loaded for every page requested from the site and not just on pages that contain the module generated content?
In other words, if I added a file called test.js to the test.info file. Will the test.js file be loaded into a page that has nothing to do with the test module? For example, while displaying any other node type?
Thank you,
--
Louay Gammo
Error in documentation for protection jQuery namespace?
The documentation above suggests wrapping code like so:
(function ($) {// All your code here
}(jQuery));
But typically the arrangement of the closing parentheses is like this:
(function ($) {// All your code here
})(jQuery); //see the difference here, jQuery is on outside
Is there a semantic difference? Should the documentation be updated?
I wondered about that too.
I wondered about that too. Which is the correct way now?
grossmann-mcs
grossmann-mcs
Correct
Correct closing:
})(jQuery);Fixed now in the article above.
and finally... any
and finally... any difference?
There is no difference
Both versions are doing the same thing. Just use the version which you prefer.
Using the hook_js_alter()
Using the hook_js_alter() example for vertical-tabs.js gave me undefined index errors for type and scope, I had to define the defaults:
<?phpfunction adaptivetheme_js_alter(&$javascript) {
$file = drupal_get_path('theme', 'adaptivetheme') . '/js/vertical-tabs.js';
$javascript['misc/vertical-tabs.js'] = drupal_js_defaults($file);
}
?>
Responsive Drupal Themes | Drupal 8 Design Initiative | Certified to Rock
Unfortunately, the "attach"
Unfortunately, the "attach" statements cause firebug to complain about a missing colon. Does anyone have a fix for that?
JQuery after an Ajax event
I just ran into a case for Drupal 7 where I needed to fire off JQuery after an Ajax event on my pages. I came up with this code and it worked really well. Note the
$('.mydiv').ajaxComplete(function() {(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);
High Rock Media | Drupal Photography | Skype: highrockmedia | Twitter
Adding JavaScript in the module's .info file
Hey, I have tried the described:
"scripts[] = somescript.js" ... in the .info file of my used theme.
Anyhow the system does always add a "?lvdcsh" to the script files link and it seems that the script does not work correct because of that, am I right?
Here is the scripts link:
<script type="text/javascript" src="http://onvedi.de/sites/all/themes/simpleclean/js/googledfp.js?lvdcsh"></script>Any suggestion?
No
That part of the URL, the querystring, should not affect your script at all.
It's added so Drupal can change 'lvdcsh' into something else when you clear the Drupal caches. Changing the URL will make the browser think it's a new script, and reload it from the server instead of fetching it from its own cache. That ensures your visitors get the latest version if you've modified something.
Any script added to the .info file of an active module or theme will be included on all pages. If it's not working, check the browser's JavaScript console for errors, or contact the person who wrote the script so they can debug it.