0

I am trying to add new fields based on the select list. I am using the following code

function my_action_plan_from($form, &$form_state) {
  $form['#tree'] = TRUE;
  $result = db_query('Select * from my_action_plan_settings ORDER BY action_type');
  $records = array();
  $i = 0;
  foreach ($result as  $record) {
    $action_lists = array_merge($records, preg_split('/[\r\n]+/', trim($record->point_of_action), -1, PREG_SPLIT_NO_EMPTY));

    $form[$action_name] = array(      
      '#type' => 'select',
      '#options' => $action_lists,
      '#attributes' => array('class' => array('enabled-for-ajax')),
      '#ajax' => array(
        'callback' => 'get_next_steps',
        'wrapper' => 'item-action-'. $record->action_id,
        'method' => 'append',
      ),
    );

  }

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Save',
  );

  return $form;
}

function get_next_steps($form, &$form_state) {
      $newform['date'] = array(
        '#type' => 'textfield',
        '#size' => 20,
      );
      $newform['note'] = array(
        '#type' => 'textarea',
      );

      $newform['percent'] = array(
        '#type' => 'textfield',
      );
      return $newform;
}

It works fine with adding new fields based on selection, but the problem is the new fields added does not appear in $form_state. The values does not get submitted to submit handler, am i doing something wrong?

* MODIFIED CODE *

Maybe i was wrong at explaining, sorry, i have posted the modified code and yes i am creating the form in my_action_plan_form(). I am not trying to use $form_state for a permanent store, I was using it to create new fields in my_action_plan() but the problem is if i set a value $form_state['storage'] = "foobar" in get_next_step(), the value is not passed to my_action_plan(). $form_state['storage'] becomes empty in my_action_plan().

function my_action_plan_form($form, &$form_state) {

  $form['#tree'] = TRUE;

  $trigger_element = !empty($form_state['triggering_element']['#name']) ? $form_state['triggering_element']['#name'] : FALSE;

  foreach ($result as  $record) {
    $action_lists = array_merge($records, preg_split('/[\r\n]+/', trim($record->point_of_action), -1, PREG_SPLIT_NO_EMPTY));
    $action_name = "action_name_" . $record->action_id;

    $form[$action_name] = array(        
      '#type' => 'fieldset',
    );

    if (empty($form_state['my_action_plan'][$action_name])) {
      $form_state['my_action_plan'][$action_name] = array();
    }

    if($trigger_element && $trigger_element == $record->action_id ) {
      if(!array_search($form_state['triggering_element']['#value'], $form_state['my_action_plan'][$action_name])) {
        $form_state['my_action_plan'][$action_name][] = $form_state['triggering_element']['#value'];
      }
    }


    $form[$action_name]['select'] = array(
      '#type' => 'select',
      '#options' => $action_lists,
      '#attributes' => array('class' => array('enabled-for-ajax')),
      '#ajax' => array(
        'callback' => 'get_next_steps',
        'wrapper' => $action_name . "-id",
      ),
    );

    if(count($form_state['my_action_plan'][$action_name]) > 0) {

        for ($i=0; $i < count($form_state['my_action_plan'][$action_name]); $i++) {

            $option = $form_state['my_action_plan'][$action_name][$i];

            $form[$action_name][$option] = array(
              '#type' => 'fieldset',
            );

            $form[$action_name][$option]['date'] = array(
              '#type' => 'textfield',
              '#size' => 20,
            );

            $form[$action_name][$option]['note'] = array(              
              '#type' => 'textarea',
            );

            $form[$action_name][$option]['percentage'] = array(
              '#type' => 'textfield',              
            );

            $submit_id = $action_name . '-' . $option . '-submit';
            $form[$action_name][$option]['submit'] = array(
              '#type' => 'fieldset',
            );

            $form[$action_name][$option]['submit'] = array(
              '#type' => 'fieldset',
            );

            $form[$action_name][$option]['submit']['value'] = array(
               '#type' => 'button',
              '#value' => 'Save ',
              '#ajax' => array(
                 'callback' => 'save_step',
                 'wrapper' => $submit_id,
              ),
            );
      }
  }

  return $form;
}

function get_next_steps($form, &$form_state) {
    return $form[$form_state['triggering_element']['#parents'][0]];
}

Please help

Deepak

2
  • You should create all the form elements in my_action_plan_form() where the $form_state can be used to determine what fields need to be created. Use get_next_steps() only to set and rebuild the form_state. Have a look at my answer for the similar question here
    – Jack-PL
    Commented Sep 10, 2013 at 21:07
  • Thank you Jack for replying, i got it working. i am using the trigger_element to create new fields. the only problem is whatever value i set in get_next_steps() gets destroyed. The value set on get_next_steps() remains persistent till [ajax_form_callback] ( api.drupal.org/api/drupal/includes!ajax.inc/function/… ) but gets destroyed in my_action_plan_form(), not sure what i am doing wrong,
    – Deepak ML
    Commented Sep 11, 2013 at 9:47

1 Answer 1

1

You should create all the form elements in my_action_plan_form().

Use ajax callback function only to change some form elements values.

Example:

/**
 * My action plan form.
 */
function my_action_plan_form($form, &$form_state) {

  $form['#tree'] = TRUE;

  // some basic form elements
  // ...

  // set the variable to determine 
  // whether the new form elements should be created or not.
  if (empty($form_state['new_form'])) {
    $form_state['new_form'] = FALSE;
  }

  // create new form elements
  if ($form_state['new_form']) {

    $form['date'] = array(
      '#type' => 'textfield',
      '#size' => 20,
    );

    $form['note'] = array(
      '#type' => 'textarea',
    );

    $form['percent'] = array(
      '#type' => 'textfield',
    );
  } 

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Save',
  );

  return $form;
}

/**
 * Ajax callback.
 * It's only to determine what part of the form should be returned. 
 * It allows making one-time changes, but is useless for permanent ones.
 */
function get_next_steps($form, &$form_state) {
  $form_state['new_form'] = TRUE;
  $form_state['rebuild'] = TRUE;
}
6
  • 1
    Good catch. Maybe add a word of explanation that callback is only there to determine what part of form should be returned. And that it allows making one-time changes, like $form_state['input'] all right, but is useless for permanent ones?
    – Mołot
    Commented Sep 11, 2013 at 11:08
  • Yes, it might be helpful. I added this explanation to ajax callback comment. Thank you.
    – Jack-PL
    Commented Sep 11, 2013 at 11:50
  • Thank you Jack, i have modified the code, the problem i am facing is $form_state['new_form'] = TRUE; does not get passed to my_action_plan_form(). dsm($form_state) is empty in my_action_plan_form(). so i am using trigger_element to add new field.
    – Deepak ML
    Commented Sep 11, 2013 at 15:47
  • yes i am using the triggering_element
    – Deepak ML
    Commented Sep 11, 2013 at 17:38
  • drupal_rebuild_form is called even if $form_state['rebuild'] is not set. "However, for forms that have not been fully executed (e.g., Ajax submissions triggered by non-buttons), there is no submit handler to set $form_state['rebuild']. It would not make sense to redisplay the identical form without an error for the user to correct, so we also rebuild error-free non-executed forms, regardless of $form_state['rebuild']. api.drupal.org/api/drupal/includes%21form.inc/function/…
    – Deepak ML
    Commented Sep 11, 2013 at 17:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.