Skip to main content
Dynamic form fields

Create Dynamic Form Fields in Drupal 7

Drupal's Form API helps developers to build complex, extensible forms with minimal code and also gives the option to make the form fields as dynamic. It means to change/create form fields based on the other field's given value. There is a cool trick to make dynamic fields in drupal.

Normally we are using #states elements to change other field's value, show/hide based on the field's given value. I think it is not possible to give dynamic values (for example, give values from a database based on the field's given value). But we could do that with #ajax elements. Let's see the trick with an example.

I want to list all students from a particular selected class using a checkboxes field. If we change any class on the select box, then the current class students should be shown in the checkboxes.

/**
 * Implementation of hook_form().
 */
function knackforge_dynamic_form($form, $form_state) {
  $class = array(0 => 'Select', 1 => 'Class 1', 2 => 'Class 2');

  $form['class_from'] = array(
    '#type' => 'select',
    '#title' => t('Class'),
    '#description' => t('Select any one of the class from the list.'),
    '#options' => $class,
    '#default_value' => $class[1],
    '#ajax' => array(
      'callback' => 'knackforge_migrate_student_list', // Callback will replace the students field with new values.
      'wrapper' => 'migrate-students-list',
      'method' => 'replace',
      'event' => 'change',
    ),
  );

  // Students checkboxes field container.
  $form['students'] = array(
    '#type' => 'container',
    '#tree' => TRUE,
    '#prefix' => '<div id="migrate-students-list">',
    '#suffix' => '</div>',
  );

  // Create default checkboxes field with default selected class's students options.
  $form['students']['list'] = array(
    '#type' => 'checkboxes',
    '#options' => _knackforge_get_student_list_options($class[1]),
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Migrate'),
  );
  return $form;
}

 

In the above form, we have used #ajax elements with change event on it. It means if we change the select box value then it will trigger the "knackforge_migrate_student_list" callback and the callback will replace the student field option values with new selected class's students. See the callback code,

/**
* Custom callback to build form fields.
*/
function knackforge_migrate_student_list($form, &$form_state) {
  $values = $form_state['values'];
  // Overwrite the student list fields with new options value.
  $form['students']['list'] = array(
    '#type' => 'checkboxes',
    '#options' => _knackforge_get_student_list_options($values['class_from']), // Api will return the class students list as array.
  );
  $form['students']['list'] = form_process_checkboxes($form['students']['list']); // Process the checkboxes fields.
  return $form['students']; // return full students field container.
}

/**
* API to return class's students list.
*/
function _knackforge_get_student_list_options($class) {
  $students = db_query('SELECT etid FROM {og_membership} WHERE entity_type = :entity_type AND gid = :gid', array(':entity_type' => 'user', 'gid' => $class))->fetchAll();
  $students_list = array();
  foreach ($students as $student) {
    $user = user_load($student->etid);
    If (in_array('student', $user->roles)) {
      $students_list[$user->uid] = $user->name; // Make array to fit with checkboxes options.
    }
  }
  return $students_list;
}

It's enough to make your form as dynamic. The same trick will work on all other fields too.

Comments