Embedding an AHAH form element into a theme_table-generated table (Drupal)
I am trying to include a Drupal form element in a table I am generating with theme_table
/theme('table',..)
. Specifically, I am trying to include a submit button with an AHAH attached.
Currently, I am just including as one cell in each row a call to drupal_render
to render my dynamically generated AHAH element. The button renders fine, but without the AHAH attached.
So, my question is: is there a way to attach an AHAH to something that is just drupal_render
ed?
If not, how else开发者_运维问答 can I attach an AJAX/AHAH call to an element in a theme_table
-generated table? I need to allow users to perform certain actions on rows of data in the table but need the page to not refresh.
TIA,
BenjyI believe AHAH only works with drupal_get_form()
. You'd have to write the AJAX yourself ( handbook page).
Maybe you could save the return value from drupal_get_form()
in a variable and pass it to the theme function?
I think this is sort of a bug but i created a very easy generic workaround :) Solution by Januz did not work for me since the table was used inside a form already and also it's only applicable to very specific use cases and not a generic solution. You can have a look at the following code and the function i wrote as an example Notice : You may probably need to modify the code to suit your needs
/**
* @param $form
* @param $form_state
* @param $form_id
*/
function mymodule_form_alter(&$form, &$form_state, $form_id) {
$test_button = array(
'test_button' => array(
'#type' => 'button',
'#value' => t('Add'),
'#name' => 'test_button',
'#id' => 'test_button',
'#weight' => 2,
'#ajax' => array(
'callback' => '_mymodule_ajax_callback',
)
)
);
$form['mytable'] = array(
'#weight' => 1,
'#theme' => 'table',
'#header' => array(
array("data" => "Item"),
),
'#rows' => array(
'data' => array(
array(
'data' => $test_button
),
)
),
);
// This is a work around, ajax elements do not work when used in drupal tables
mymodule_table_ajax_workaround($test_button, $form, $form_state);
}
/**
* Ajax enabled form elements do not work then used inside a drupal table and rendered via theme_table
* This is a workaround to address the issue
* @param $elements
* @param $form
* @param $form_state
*/
function mymodule_table_ajax_workaround($elements, &$form, &$form_state) {
foreach ($elements as $element_name => $element_info) {
drupal_add_js(array('ajax' => array(
$element_name => array(
'callback' => $element_info['#ajax']['callback'],
'event' => 'mousedown',
'keypress' => true,
'prevent' => 'click',
'url' => '/system/ajax',
'submit' => array(
'_triggering_element_name' => $element_name . '_fake',
'_triggering_element_value' => $element_info['#value'],
)
),
)), 'setting');
$form['form_ajax_workaround'][$element_name] = array(
'#name' => $element_name . '_fake',
'#input' => true,
'#value' => $element_info['#value'],
'#ajax' => array(
'callback' => $element_info['#ajax']['callback']
)
);
}
}
You can do this via theme function and table generation. AHAH will work. The only problem is when you have multiple "tables", things start getting hairy.
Short explanation (correct me if I am wrong!): AJAX enabled form elements appear invisible to Drupal's Form API when they remain inside a "#theme" => "table"
render array. This is probably due to render()
using element_children()
which does not look into a table's #header
or #rows
elements. A way to workaround this is to add dummy elements to the form which are visible to the Form API and bind AJAX events to the original elements to trigger the dummy elements.
I forked Sina Salek's great workaround for Drupal 7, main differences are:
- Different form field keys, names and ID's are allowed,
- The callback from the JS AJAX settings object is removed since it does not seem to exist in JS,
- Added the base path variable to the AJAX URL for sites that are not installed in the web root,
- Use
"#type" => "value"
for the dummy buttons instead of the internal options"#input" => TRUE
, - The dummy element is available through the exact same name as the original element, without a "_fake" postfix, since the original elements are invisible to the Form API and the dummy elements do not appear in the DOM,
- The full #ajax array is copied to the dummy element instead of just the callback element so other settings (ie. for the throbber) remain.
- Allows the user to set custom JS AJAX options per button.
Example of implementing the workaround per AJAX enabled element when building a form:
/**
* My form.
*/
function MY_MODULE_my_form($form, &$form_state) {
// Define button. NB: An ID and name are required!
$my_button = array(
'#type' => 'button',
'#id' => 'test_button',
'#name' => 'test_button',
'#value' => t('Button label'),
'#ajax' => array('callback' => '_MY_MODULE_ajax_callback'),
);
// Call table AJAX workaround function on the button.
MY_MODULE_table_ajax_workaround($my_button, $form);
// Define table.
$form['my_table'] = array(
'#theme' => 'table',
'#header' => array(
array('data' => t('Column header')),
),
'#rows' => array(
'data' => array(
array('data' => $my_button),
)
),
);
return $form;
}
/**
* Workaround for AJAX enabled form elements that remain inside tables.
*
* Problem: AJAX enabled form elements appear invisible to Drupal's Form API
* when they remain inside a #theme => table render array. This is probably due
* to render() using element_children() which does not look into a table's
* #header or #rows elements.
*
* Workaround: Add dummy elements to the form which are visible to the Form API
* and bind AJAX events to the original elements to trigger the dummy elements.
*
* Based on:
* @link http://stackoverflow.com/questions/1981781
*
* Shared at:
* @link http://stackoverflow.com/a/31098784/328272
*
* Another workaround is the render elements using custom theme functions, but
* this seems slightly more complicated and rendered elements are no longer
* alterable.
* @link https://www.drupal.org/node/2101557#comment-7920151
*/
function MY_MODULE_table_ajax_workaround($element, &$form, $js_ajax_options = array()) {
// Add dummy element.
$form['table_ajax_workaround'][$element['#id']] = array(
'#type' => 'value',
'#name' => $element['#name'],
'#value' => $element['#value'],
'#ajax' => $element['#ajax'],
);
// Bind AJAX event to the original element, default properties are used. See
// Drupal.ajax in misc/ajax.js.
$js_setting['ajax'][$element['#id']] = drupal_array_merge_deep(array(
'event' => 'mousedown',
'keypress' => true, // Use lowercase booleans to support IE.
'prevent' => 'click',
'url' => base_path() . 'system/ajax',
'submit' => array(
'_triggering_element_name' => $element['#name'],
'_triggering_element_value' => $element['#value'],
),
), $js_ajax_options);
// Add JS setting.
drupal_add_js($js_setting, 'setting');
}
精彩评论