7.x common.inc drupal_process_attached($elements, $group = JS_DEFAULT, $dependency_check = FALSE, $every_page = NULL)

Adds attachments to a render() structure.

Libraries, JavaScript, CSS and other types of custom structures are attached to elements using the #attached property. The #attached property is an associative array, where the keys are the attachment types and the values are the attached data. For example:

$build['#attached'] = array(
  'js' => array(drupal_get_path('module', 'taxonomy') . '/taxonomy.js'),
  'css' => array(drupal_get_path('module', 'taxonomy') . '/taxonomy.css'),
);

'js', 'css', and 'library' are types that get special handling. For any other kind of attached data, the array key must be the full name of the callback function and each value an array of arguments. For example:

$build['#attached']['drupal_add_http_header'] = array(
  array('Content-Type', 'application/rss+xml; charset=utf-8'),
);

External 'js' and 'css' files can also be loaded. For example:

$build['#attached']['js'] = array(
  'http://code.jquery.com/jquery-1.4.2.min.js' => array(
    'type' => 'external',
  ),
);

Parameters

$elements: The structured array describing the data being rendered.

$group: The default group of JavaScript and CSS being added. This is only applied to the stylesheets and JavaScript items that don't have an explicit group assigned to them.

$dependency_check: When TRUE, will exit if a given library's dependencies are missing. When set to FALSE, will continue to add the libraries, even though one or more dependencies are missing. Defaults to FALSE.

$every_page: Set to TRUE to indicate that the attachments are added to every page on the site. Only attachments with the every_page flag set to TRUE can participate in JavaScript/CSS aggregation.

Return value

FALSE if there were any missing library dependencies; TRUE if all library dependencies were met.

See also

drupal_add_library()

drupal_add_js()

drupal_add_css()

drupal_render()

3 calls to drupal_process_attached()
drupal_add_library in includes/common.inc
Adds multiple JavaScript or CSS files at the same time.
drupal_render in includes/common.inc
Renders HTML given a structured array tree.
drupal_render_cache_get in includes/common.inc
Gets the rendered output of a renderable element from the cache.

File

includes/common.inc, line 4614
Common functions that many Drupal modules will need to reference.

Code

function drupal_process_attached($elements, $group = JS_DEFAULT, $dependency_check = FALSE, $every_page = NULL) {
  // Add defaults to the special attached structures that should be processed differently.
  $elements['#attached'] += array(
    'library' => array(),
    'js' => array(),
    'css' => array(),
  );

  // Add the libraries first.
  $success = TRUE;
  foreach ($elements['#attached']['library'] as $library) {
    if (drupal_add_library($library[0], $library[1], $every_page) === FALSE) {
      $success = FALSE;
      // Exit if the dependency is missing.
      if ($dependency_check) {
        return $success;
      }
    }
  }
  unset($elements['#attached']['library']);

  // Add both the JavaScript and the CSS.
  // The parameters for drupal_add_js() and drupal_add_css() require special
  // handling.
  foreach (array('js', 'css') as $type) {
    foreach ($elements['#attached'][$type] as $data => $options) {
      // If the value is not an array, it's a filename and passed as first
      // (and only) argument.
      if (!is_array($options)) {
        $data = $options;
        $options = NULL;
      }
      // In some cases, the first parameter ($data) is an array. Arrays can't be
      // passed as keys in PHP, so we have to get $data from the value array.
      if (is_numeric($data)) {
        $data = $options['data'];
        unset($options['data']);
      }
      // Apply the default group if it isn't explicitly given.
      if (!isset($options['group'])) {
        $options['group'] = $group;
      }
      // Set the every_page flag if one was passed.
      if (isset($every_page)) {
        $options['every_page'] = $every_page;
      }
      call_user_func('drupal_add_' . $type, $data, $options);
    }
    unset($elements['#attached'][$type]);
  }

  // Add additional types of attachments specified in the render() structure.
  // Libraries, JavaScript and CSS have been added already, as they require
  // special handling.
  foreach ($elements['#attached'] as $callback => $options) {
    if (function_exists($callback)) {
      foreach ($elements['#attached'][$callback] as $args) {
        call_user_func_array($callback, $args);
      }
    }
  }

  return $success;
}

Comments

Garrett Albright’s picture

There's no examples for how to add a library using the #attached parameter of the render array, so here's one. Basically, each value of the 'library' array should be an array with two elements corresponding to the first two arguments of drupal_add_library(). To add, for example, the jQuery Cookie library that the System module provides:

$build['attached']['library'] = array(
  array('system', 'jquery.cookie'),
);
pixelsmash’s picture

Since it's not given, here's a quick example of how you can use #attached to add javascript settings (which you normally would do like this)

  $build['#attached']['js'] = array(
      'type' => 'setting',
      'data' => array('my_module' => array(
        'samplevalue' => 3,
      )),
    );
kingandy’s picture

I am pretty sure that needs to be $build['#attached']['js'][] - the js element is an array of things-to-attach. So:

  $build['#attached']['js'][] = array(
      'type' => 'setting',
      'data' => array('my_module' => array(
        'samplevalue' => 3,
      )),
    );
bucefal91’s picture

It took me quite a bit to figure it out. If you want the 2nd argument to drupal_add_js() to be an array, here's how you do it:

$element['#attached']['js']['PATH_TO_JS'] = array('weight' => 1000);
dman’s picture

Inspecting the code itself shows how #attached actually just hands the processing off to drupal_add_xxx(), so with that in mind, I was able to insert a little inline JS for a field also.
You can split each attached resource line into an array, and then set the 'type'=>'inline' or 'type'=>'external' as needed.

To take an example off the net and make it work in a FAPI-compatible way

To follow the Instructions for adding the Freebase Search widget to a form element, the official docs say do this:

<link type="text/css" rel="stylesheet" href="https://www.gstatic.com/freebase/suggest/4_2/suggest.min.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<script type="text/javascript" src="https://www.gstatic.com/freebase/suggest/4_2/suggest.min.js"></script>
<script type="text/javascript">
$(function() {
  $("#myinput").suggest({filter:'(all type:/film/director)'});
});
</script>

To Drupalize that in FormAPI, I can go:

  // Add Freebase Search widget (formerly Freebase Suggest)
  $form['search']['chosen_type']['#attached'] = array(
    'css' => array(
      array(
        'data' => 'https://www.gstatic.com/freebase/suggest/4_2/suggest.min.css',
        'type' => 'external',
      ),
    ),
    'js' => array(
      array(
        'data' => 'https://www.gstatic.com/freebase/suggest/4_2/suggest.min.js',
        'type' => 'external',
      ),
      array(
       'data' => 'jQuery(function() { jQuery("#edit-freebase-topic-search-chosen-type").suggest({filter:"(all type:/film/director)"});});' ,
       'type' => 'inline'
      ),
    ),
  );

And it works!

kingandy’s picture

For what it's worth, if your data is not an array - which is everything except settings - you can use it as the attachment array key. (Personally I'd avoid doing this with inline script as well, because ugh characters.) So the above code could be presented as:

  // Add Freebase Search widget (formerly Freebase Suggest)
  $form['search']['chosen_type']['#attached'] = array(
    'css' => array(
      'https://www.gstatic.com/freebase/suggest/4_2/suggest.min.css' => array(
        'type' => 'external',
      ),
    ),
    'js' => array(
      'https://www.gstatic.com/freebase/suggest/4_2/suggest.min.js' => array(
        'type' => 'external',
      ),
      array(
       'data' => 'jQuery(function() { jQuery("#edit-freebase-topic-search-chosen-type").suggest({filter:"(all type:/film/director)"});});' ,
       'type' => 'inline'
      ),
    ),
  );
parth vora’s picture

Hi,

Is there anything wrong in below code, I'm trying to attach inline js inside a form, but it didn't working out

$form['#attached']['js'][] = array(
'data' => 'jQuery(function() { console.log("test"); });',
'type' => 'inline',
);

Thanks

aaron.ferris’s picture

To add inline css to a block, using the '#attached' approach, the format should be;

$block['content']['#attached']['css'] = array(
  'your css' => array('type' => 'inline'),
);