7 system.api.php hook_js_alter(&$javascript)
8 theme.api.php hook_js_alter(&$javascript, \Drupal\Core\Asset\AttachedAssetsInterface $assets)

Perform necessary alterations to the JavaScript before it is presented on the page.

Parameters

$javascript: An array of all JavaScript being presented on the page.

See also

drupal_add_js()

drupal_get_js()

drupal_js_defaults()

Related topics

2 functions implement hook_js_alter()

Note: this list is generated by pattern matching, so it may include some functions that are not actually implementations of this hook.

locale_js_alter in modules/locale/locale.module
Implements hook_js_alter().
simpletest_js_alter in modules/simpletest/simpletest.module
Implements hook_js_alter().
1 invocation of hook_js_alter()
drupal_get_js in includes/common.inc
Returns a themed presentation of all JavaScript code for the current page.

File

modules/system/system.api.php, line 768
Hooks provided by Drupal core and the System module.

Code

function hook_js_alter(&$javascript) {
  // Swap out jQuery to use an updated version of the library.
  $javascript ['misc/jquery.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js';
}

Comments

When following the example above my logs were filling with drupal_get_js out of scope errors. Following the commit here on adaptive theme helped me fix.

http://drupalcode.org/project/adaptivetheme.git/blob_plain/b4acfa587348b...

Works

$file = drupal_get_path('theme', 'pp') . '/js/autocomplete.js';
$javascript['misc/autocomplete.js'] = drupal_js_defaults($file);
Errors

$file = drupal_get_path('theme', 'pp') . '/js/autocomplete.js';
$javascript['misc/autocomplete.js']['data'] =$file;

This works for me:

function my_module_js_alter(&$javascript) {
    global $base_url;
    $jQuery_version = '1.7.2';
    //$jQuery_local = $base_url.'/'.drupal_get_path('module', 'my_module').'/jquery-1.7.2.min.js';
    $jQuery_local = $base_url.'/'.drupal_get_path('module', 'my_module').'/jquery-1.7.2.min.js?v='.$jQuery_version;
    $jQuery_cdn = 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js';

    $javascript['misc/jquery.js']['data']    = $jQuery_cdn;
    $javascript['misc/jquery.js']['version'] = $jQuery_version;

    $group  = $javascript['misc/jquery.js']['group']  = JS_LIBRARY;
    $weight = $javascript['misc/jquery.js']['weight'] = -20;
   
    drupal_add_js('window.jQuery || document.write(\'<script type="text/javascript" src="'.$jQuery_local.'"><\/script>\')',
        array('type'=>'inline', 'scope'=>'header', 'group'=>$group, 'every_page'=>TRUE, 'weight'=>$weight));
}

Thk for posting. I saw very examples and not work but your code yes !!!
See you

Thanks... I test method 3 from http://drupal.org/node/1058168 but not works.. al least for me.

Hi,

I am using below function. But it's not taking preprocess function whether true or false, 1 or 0, Please suggest how to set it.
$javascript['modules/field/modules/text/text.js']['preprocess '] = FALSE;
Getting below error:
Notice: Undefined index: preprocess in drupal_get_js() (line 4351 of C:\xamp\xampplite\htdocs\drupal\includes\common.inc).

Code is

function drupalmodule_js_alter(&$javascript) {
$javascript['modules/field/modules/text/text.js']['type'] = 'file';
$javascript['modules/field/modules/text/text.js']['scope'] = 'header';
$javascript['modules/field/modules/text/text.js']['every_page'] = TRUE;
$javascript['modules/field/modules/text/text.js']['weight'] = -20;
$javascript['modules/field/modules/text/text.js']['group'] = 0;
$javascript['modules/field/modules/text/text.js']['preprocess '] = FALSE;
$javascript['modules/field/modules/text/text.js']['defer'] = '';
$javascript['modules/field/modules/text/text.js']['cache'] = '';
$javascript['modules/field/modules/text/text.js']['data'] = drupal_get_path('module', 'drupalmodule') . '/drupalmodule.js';
}

Don't set the 'preprocess' value and set 'cache' to FALSE. Drupal does not care about preprocess if the script is not cached (i.e. aggregated in one big file).

This fixed the errors for me:
Download a copy of jquery.form.js at http://malsup.github.io/jquery.form.js.
Put it in your theme. Don't overwrite core and use an hook_js_alter.
Thanks all

function THEMENAME_js_alter(&$javascript) {
    $javascript['misc/jquery.form.js']['data'] = drupal_get_path('theme', 'THEMENAME') . '/js/jquery.form.js';
    $javascript['misc/jquery.form.js']['scope'] = 'header';
    $javascript['misc/jquery.form.js']['group'] = 'JS_LIBRARY';
    $javascript['misc/jquery.form.js']['weight'] = '100';
    $javascript['misc/jquery.form.js']['every_page'] = TRUE;
    $javascript['misc/jquery.form.js']['type'] = 'file';
    $javascript['misc/jquery.form.js']['preprocess'] = 'TRUE';
    $javascript['misc/jquery.form.js']['cache'] = 'TRUE';
    $javascript['misc/jquery.form.js']['defer'] = 'TRUE';
}

Ow. It fixed my ajax webform submission in IE8. I did have an error occured message

For Drupal 6 you can use:
http://drupal.org/project/jsalter

Inside template.php file, I made the following function:

function MYTHEME_js_alter(&$javascript) {
print "Hello World!!!";
}

Just for testing purpose, I tried to print a text "Hello World!!!" in the above function. It displayed the output "Hello World!!!" twice.

Why is it displaying the output twice ?

I believe it's because hooks run whenever they are needed.. in this case you're altering javascripts that are loaded, so if you have 2 javascripts in your theme, it would run twice. I think you just need to wrap that print command into some logic based on which javascript you're targeting (this is how hook_form_alter works too).

We can easily unset unused js using this hook function. It would prevent to load unused js on page that will reduce extra overhead on page. We can write this function anywhere either in custom module or template.php inside your theme.

Say I need to unset test.js then I would write code in following way:

<?php
function general_js_alter(&$javascript) {
  
$test_js_path = path_to_theme() . '/js/test.js';
   unset(
$javascript[$test_js_path]); 
}
?>

Can we use this to set variables to Drupal.settings?

For example:

<?php
function mymodule_js_alter() {
  global
$user;

 
drupal_add_js(array('mymodule' => array('time' => time())), 'setting');
 
drupal_add_js(array('mymodule' => array('user' => $user->uid)), 'setting');
}
?>

It's correct?

Not sure, but that might create an infinite loop. drupal_add_js invokes mymodule_js_alter which calls drupal_add_js which ...

You could set a static variable and a test for it, so that your drupal_add_js statements are only run once. Or (better?) don't call drupal_add_js in mymodule_js_alter. Instead, look at the array parameter passed into module_js_alter, and add to that.

This seems to work:

<?php
/**
 * Implements hook_js_alter().
 */
function cybercourse_base_js_alter(&$javascript) {
 
//Make sure that JS error handling code is included.
 
global $base_url;
 
$path = drupal_get_path('module', 'cybercourse_base')
        .
'/js/cybercourse_base_error_handling.js';
 
$javascript[$path] = array(
   
'data' => $base_url. '/' . $path,
   
'scope' => 'header',
   
'group' => 'JS_LIBRARY',
   
'every_page' => TRUE,
   
'type' => 'file',
   
'cache' => TRUE,
   
'weight' => 0,
   
'preprocess' => 1,
   
'defer' => 0,
  );
}
?>

Just got into this function too to alter "misc/autocomplete.js" and the issue causing the "Notice: Undefined index: scope in drupal_get_js() (line 4309 of C:\xampp\htdocs\[DRUPAL_DIR]\includes\common.inc)." error is that there are times when the hook is called but "misc/autocomplete.js" is not yet in the array w/c just adds

[misc/autocomplete.js] => Array(
  [data] => [your_custom_js],
)

to the array but the scope, type, and other attributes are not there. So we first need to check if the array key exists like so:

if (isset($javascript['misc/autocomplete.js'])) {
  $file = drupal_get_path('module', 'mymodule') . '/autocomplete.js';
  $javascript['misc/autocomplete.js']['data'] = $file;
}

That solves it. :)