drupal_add_js and drupal_add_css in hook_form_alter and hook_form in Drupal 6

Mon, Apr 20, 2009 by Afraaz

The idea of adding custom CSS or JS to a form is a very simple task. With one call
to drupal_add_css, a form can be themed any which way. A call to drupal_add_js can add
effects to a form for a better user experience.

Adding CSS using drupal_add_css allows for CSS preprocessing, which is the process of
aggregating a bunch of separate CSS files into one file that is then compressed by
removing all extraneous white space. This will save on page load time and will bypass
the limit that IE has on the amount of CSS files that can be imported. Using drupal_add_js
also allows you to cache the JS files as well. Using these two functions in Drupal 5
and Drupal 6 are almost identical. However in Drupal 6, the parameters for each of the
functions are passed in an associative array.

With the release of Drupal 6, the form API was slightly changed as well. Here's a
link to the complete list of changes in the FAPI (Form API): http://drupal.org/node/144132.
A big change in Drupal 6 was the fact that forms were being cached. So adding CSS files and JS
files in hook_form_alter or hook_form would lead to issues if the form was reloaded after failing validation.

Let's take an example in Drupal 6:

example.module

function example_form_alter(&$form, $form_state, $form_id) {
  switch ($form_id) {
    case 'page_node_form':
      drupal_add_js('file.js');
      $form['foo'] = array(
        '#type' => 'textfield',
        '#title' => t('Bar'),
        '#required' => TRUE,
      );
     break;
  }
}

The above code will add a file named "file.js" to the form for adding a page node.

file.js

Drupal.behaviors.alertTest = function () {
  alert('foo');
};

The above code will alert the word 'foo'. Of course this just an example.

Now when the form loads the alert will fire off and show an alert box. If the form
is submitted and fails validation, you'll notice that the alert will not be triggered.
This is because hook_form_alter() will not be called again if the form is cached for efficiency. We
could just set the form to not be cached, but then we'd lose out on the efficiency factor. There are
multiple ways of making sure the JS and CSS get added properly. One way would be to add it through the
after_build property of the form, or use hook_init with a couple of if statements to re-add the files. Another
way it can be done is to declare a themeing function or template for the form and add it in there. Here's an example:


function example_form_alter(&$form, $form_state, $form_id) {
  switch ($form_id) {
    case 'page_node_form':
      $form['foo'] = array(
        '#type' => 'textfield',
        '#title' => t('Bar'),
        '#required' => TRUE,
      );
     break;
  }
}

Note the drupal_add_js call has been removed from hook_form_alter.

file.js

Drupal.behaviors.alertTest = function () {
  alert('foo');
};

This file will remain unchanged.

We will now need to implement hook_theme, like so:

function example_theme($existing, $type, $theme, $path) {
  return array(
    'page_node_form' => array(
      'arguments' => array('form' => NULL),
    ),
  );
}

The themeing function is named the same as the form id of the form. Make sure to
clear your theme registry via admin/settings/performance and clicking the
"Clear cached data" button. This particular implementation states that we will
provide a themeing function rather than a themeing file (.tpl.php). Themeing
functions are a tad faster than theme files since there is no need to check for
alternative templates. The downside to a function is that there isn't a preprocess
function.

Here's the declaration and implementation of the themeing function:

function theme_page_node_form($form) {
  drupal_add_js('file.js');
  return drupal_render($form);
}

There are many other things we can do with hook_theme but in this simple case, the
above will suffice.

"The Interweb! My ~ away from ~"

Catherine Ellis posted on November 13, 2009 11:00 am

I've just started writing my own modules with Drupal. If I have a site with a lot of forms is it worth calling css files on the fly for anonymous users or would it be better sticking them all in .info file?

chakrapani posted on November 6, 2009 7:39 am

Hii thank You very much!!! i've been struggling on this for more than 30 hrs and finally landed at your post :) thanks once again. Nice work!!

Tanc posted on June 10, 2009 4:15 am

Thanks for this, it was exactly what I was looking for. I was writing a quick bit of jQuery functionality to count down the number of characters left in a restricted length text field and came across problems with validation. This sorted it nicely.

Anonymous posted on May 8, 2009 8:33 pm

Hi,thanks for the tid bit. However, in the above example, I'm using a themeing function. I don't believe we can use a preprocessor for themeing functions. I tend use functions over templates, as they are a tad faster. However, I will keep this in mind when using views and other external modules. Thank you, once again.

Anonymous posted on May 8, 2009 7:42 pm

They could have problems with external modules (like "views"). Try your trick with the form id "views_exposed_form" and you will see that this function disturbs the filter form theming.
So, use YOURTHEME_preprocess_YOURFORM(&$vars) instead of YOURTHEME_YOURFORM($form) for adding CSS and JS files.

Bye ! ;)

Jim posted on April 21, 2009 12:23 pm

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <h2>
  • Lines and paragraphs break automatically.

More information about formatting options