While reading the Ajax framework documentation I came across mention of the #ajax
property. I know from poking through the code that there are others of these properties with hash signs in front of them. What does the hash sign signify? What are these properties all about?
-
Hopefully it's ok for me to want to add "pound sign" somewhere here on this page (since that's a search term I was using to try figure this out, when "hash" wasn't getting me too helpful results).– Max StarkenburgCommented Sep 13, 2019 at 17:34
2 Answers
This is to do with render arrays in general, it's not just specific to AJAX or the form API (although the form API uses render arrays exclusively for building up it's content).
Put simply, array keys in a render array without a #
in front of the name are seen as children of the render array, and are subsequently rendered themselves (recursively).
Those with a #
in front of them are seen as meta data/variables for the render array to use as necessary, and are not themselves rendered.
The render array docs (linked to above) actually put this nice and succinctly:
A render array is a classic Drupal structured array that provides data (probably nested) along with hints as to how it should be rendered (properties, like #type).
The #
keys are the 'hints' that the above paragraph is talking about, the non-#
keys are the nested data.
I'd thoroughly recommend giving that page a read, it does a good job of de-mystifying the whole render array thing, and provides code examples.
There's also another small explanation/code example on the Theming the page docs which might be useful.
Render arrays are used all over the place in Drupal (forms, themes, general markup, etc.) so knowing a good bit about them will help a lot with future Drupal development.
The form API uses a # in front of all the properties, to make a distinction between properties, and child elements. In the following code, $form['choice_wrapper']['choice']
is a child element, while $form['choice_wrapper']['#tree']
is a property.
// Add a wrapper for the choices and more button.
$form['choice_wrapper'] = array(
'#tree' => FALSE,
'#weight' => -4,
'#prefix' => '<div class="clearfix" id="poll-choice-wrapper">',
'#suffix' => '</div>',
);
// Container for just the poll choices.
$form['choice_wrapper']['choice'] = array(
'#prefix' => '<div id="poll-choices">',
'#suffix' => '</div>',
'#theme' => 'poll_choices',
);
All those properties are listed in the Form API reference. There are many properties, but they are all about rendering, validation, and submission.
The reason to use a prefix for properties is to able to quick filter out the properties from the child elements, which is useful when they need to be rendered, for example with drupal_render(), which contains the following code.
// Get the children of the element, sorted by weight.
$children = element_children($elements, TRUE);
// Initialize this element's #children, unless a #pre_render callback already
// preset #children.
if (!isset($elements['#children'])) {
$elements['#children'] = '';
}
// Call the element's #theme function if it is set. Then any children of the
// element have to be rendered there.
if (isset($elements['#theme'])) {
$elements['#children'] = theme($elements['#theme'], $elements);
}
// If #theme was not set and the element has children, render them now.
// This is the same process as drupal_render_children() but is inlined
// for speed.
if ($elements['#children'] == '') {
foreach ($children as $key) {
$elements['#children'] .= drupal_render($elements[$key]);
}
}
If you look at element_children(), you will notice the code to filter out properties is the following one.
// Filter out properties from the element, leaving only children.
$children = array();
$sortable = FALSE;
foreach ($elements as $key => $value) {
if ($key === '' || $key[0] !== '#') {
$children[$key] = $value;
if (is_array($value) && isset($value['#weight'])) {
$sortable = TRUE;
}
}
}