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

Status: Active » Closed (outdated)

Automatically closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.