How to calculate field values using Webform 3.0 and Drupal 7

About Drupal CMS

So the problem was the following: I'm running a Drupal 7 website with Webform 3.0 and wanted to be able to calculate some field values based on other input fields. I.e. height and width are given and the area is returned on the next page of the webform.

A fairly simple problem, with (in the end) a simple solution, but one I've not been able to find on the web and required a significant amount of real hard-core code debugging.

The solution

First of all, I didn't want to do this using jQuery or javascript. Instead I decided to develop an add-on module "webform-calc" much like webform-validate.

Overriding hook_form_alter()

The key to be able to do anything to a form is to override hook_form_alter(). In doing so you can add additional functionality. In this case I added an additional validation function. The benefit here is that a validation function is called after all user input data is received and the user presses the next button. Any values changed at this stage will still be stored in the database, and can be retrieved later for further usage.

The if-statement is needed to make sure I'm only adding the validation fuction to my specific webform.

/**
 * Implements hook_form_alter().
 */
function webform_calc_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'webform_client_form_34') {
    $form['#validate'][] = 'webform_calc_validate';
  }
}

Implementing webform_calc_validate()

Using a switch-satement it is determined on which page of the webform we are. Then the just entered width and height are retrieved from the form data structure and the area is calculated. The area is stored in the right structure using form_set_value().

On the second page the area value is retrieved from storage (the textfield ‘area’ has index 4 - use the devel module to determine the indices), and another textfield (with index 11) is updated to display the previously calculated area.

function webform_calc_validate($form, &$form_state) {
  switch($form_state['input']['details']['page_num']) {
    case '1':
      $width = $form_state['input']['submitted']['width'];
      $height = $form_state['input']['submitted']['height'];
      
      $area = $width * $height;
      form_set_value(
        $form['submitted']['area'], $area, $form_state);
      break;
    case '2':
    	$area = $form_state['storage']['submitted'][4];
      $form_state['webform']['component_tree']['children']
        [11]['value'] = 'Total area: ' . $area; 
      break;
  }
  return $form;
} 

The whole trick is not the complexity of the algorithms, but the complexity of the form's datastructures. Retrieving and storing of the datavalues must be done in exactly the right stuctures for them to have any effect.

© 2011 Rob Rutten / R2 Marketing Internet Marketing & Digital Media, all rights reserved.