Hi
I use drupal_execute to modify the node via AJAX. The idea is that I load the node form into overlay and then use drupal_execute to save it. Here is the problem I faced while doing it:
The form includes couple checkboxes (one was created with cck and one with form_alter). Here is how I save the node in my AJAX handler on the server side:
module_load_include('inc', 'node', 'node.pages');
$node = node_load($nid);
$form_state['values'] = $_POST;
$form_state['values']['op'] = t('Save');
// Since our form is always the same we need to use refresh changed value
// from the loaded node, otherwice we will get Content Modified by another user
$form_state['values']['changed'] = $node->changed;
drupal_execute('product_node_form', $form_state, $node);
- $nid comes from the client through AJAX
So here what happens when drupal_execute gets called. The assumption here is that you want to uncheck the chekbox on the node form with AJAX:
- drupal_prepare_form sets #programmed property $form['#programmed'] = isset($form['#post']);
- form_builder sets #programmed property for each element $form[$key]['#programmed'] = $form['#programmed'];
- because of it when form_builder gets executed for each field recursively and goes into _form_builder_handle_input_element, the code execution skips this function:
if (!$form['#programmed'] || isset($edit)) {
// Call #type_value to set the form value;
if (function_exists($function)) {
$form['#value'] = $function($form, $edit);
}
if (!isset($form['#value']) && isset($edit)) {
$form['#value'] = $edit;
}
}
because we got #programmed property set on our element + $edit is null because browser doesnt send empty checkboxes with POST.
Instead, code execution continues into the following section of the _form_builder_handle_input_element() function:
// Load defaults.
if (!isset($form['#value'])) {
// Call #type_value without a second argument to request default_value handling.
if (function_exists($function)) {
$form['#value'] = $function($form);
}
// Final catch. If we haven't set a value yet, use the explicit default value.
// Avoid image buttons (which come with garbage value), so we only get value
// for the button actually clicked.
if (!isset($form['#value']) && empty($form['#has_garbage_value'])) {
$form['#value'] = isset($form['#default_value']) ? $form['#default_value'] : '';
}
}
and it will load default value for the checkbox instead of unsetting it..
Basically if your default value for the checkbox is 1 - you wont be able to unset the checkbox using drupal_execute()..
To overcome this problem in Drupal 6 I had to add empty checkbox values to the $form_state to make it look like browser sent them:
if(!isset($form_state['values']['status_checkbox'])) {
$form_state['values']['status_checkbox'] = array();
}
Hope it will help someone to save couple hours..
Looks like _form_builder_handle_input_element function was redone in Drupal 7 and 8, but I didn't have a chance to test this specific use case.
Comments