Jahangir Alam Jahangir Alam - 2 months ago 35
PHP Question

Cascaded select list as a custom field using hook_field_widget_form in drupal 7

Problem

I have written a Drupal custom module for a custom field.
The field contains three cascaded select list.
I am populating the lists using javascript.

Now I need to populate it inside "hook_field_widget_form" hook.

My hook_field_widget_form is as below:



/**
* Implements hook_field_widget_form().
*/
function custom_select_list_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
$node = menu_get_object();

$division = isset($node->field_division_custom_select['und'][0]['division']) ? $node->field_division_custom_select['und'][0]['division'] : '';
$district = isset($node->field_division_custom_select['und'][0]['district']) ? $node->field_division_custom_select['und'][0]['district'] : '';
$thana = isset($node->field_division_custom_select['und'][0]['thana']) ? $node->field_division_custom_select['und'][0]['thana'] : '';

drupal_add_js(array('custom_select_list' => array('division' => $division, 'district' => $district, 'thana' => $thana )), array('type' => 'setting'));

switch ($instance['widget']['type']) {
case 'custom_field_widget' :
$element['custom_select_field'] = array(
'#type' => 'fieldset',
'#title' => $element['#title'],
'#tree' => TRUE,
);
$element['custom_select_field']['division'] = array(
'#type' => 'select',
'#title' => t('Division'),
'#default_value' => isset($items[$delta]['division']) ? $items[$delta]['division'] : isset($node->field_division_custom_select['und'][0]['division']) ? $node->field_division_custom_select['und'][0]['division'] : '',
'#required' => $element['#required'],
'#id' => 'division-select-list',
'#attributes' => array('class' => array('selectpicker'), 'title' => t('Thana') ),
);
$element['custom_select_field']['district'] = array(
'#type' => 'select',
'#title' => t('District'),
'#default_value' => isset($items[$delta]['district']) ? $items[$delta]['district'] : isset($node->field_division_custom_select['und'][0]['district']) ? $node->field_division_custom_select['und'][0]['district'] : '',
'#required' => $element['#required'],
'#id' => 'district-select-list',
'#attributes' => array( 'class' => array('selectpicker'), 'title' => t('Thana') ),
);
$element['custom_select_field']['thana'] = array(
'#type' => 'select',
'#title' => t('Thana'),
'#default_value' => isset($items[$delta]['thana']) ? $items[$delta]['thana'] : isset($node->field_division_custom_select['und'][0]['thana']) ? $node->field_division_custom_select['und'][0]['thana'] : '',
'#required' => $element['#required'],
'#id' => 'thana-select-list',
'#attributes' => array('class' => array('selectpicker'), 'title' => t('Thana') ),
);
break;
}
return $element;
}





Since I am populating the select lists using javascript there is no '#options' in each $element.

I have googled a lot for how to populate cascaded select lists inside hook method.

So far I have got AJAX callback method to populate select lists.
But I could not understand the method.

Suppose I have 2 select list named "post" and "bynavn". for these 2 select lists I have to write the following in hook method:



$element['post'] = array(
'#type' => 'select',
'#title' => t('post'),
'#default_value' => isset($items[$delta]['post']) ? $items[$delta]['post'] : NULL,
'#options' => array(
'1' => 'One',
'2' => 'Two',
),
'#ajax' => array(
'callback' => 'dad_test_callback',
'wrapper' => 'test-div',
),
);

$element['bynavn'] = array(
'#type' => 'select',
'#title' => t('Bynavn'),
'#prefix' => '<div id="test-div">',
'#suffix' => '</div>',
'#default_value' => isset($items[$delta]['bynavn']) ? $items[$delta]['bynavn'] : NULL,
);





and the callback function is as follows:



function dad_test_callback($form, $form_state) {
$field_name = $form_state['custom_select_list']['field_data']['field_name'];
$delta = $form_state['custom_select_list']['field_data']['delta'];
$langcode = $form_state['custom_select_list']['field_data']['langcode'];
$arr = array(
'3' => 'Two',
'1' => 'one',
'2' => 'Three',
);
$form[$field_name][$langcode][$delta]['bynavn']['#options'] = $arr;
return $form[$field_name][$langcode][$delta]['bynavn'];
}





But It can not populate the second select list.

If someone give me some link to related documentation or give an answer explaining how does AJAX callback method work it would be helpful for me.

thanks in advance.

Answer

I have solved the issue myself. In previous version-

  1. I created initial select list with no "#options" in "hook_field_widget_form" function.

  2. I populated the division list using javascript. Then after selecting division I populated district list and similarly populated thana list by selecting district.

Which generated error when I submit the form.

Now -

I have declared initial Division list, District list and Thana list inside "custom_select_list_field_widget_form" function.

$division_arr = array(
  '1' => 'Division 1',
  '2' => 'Division 2',
  '3' => 'Division 3',
  '4' => 'Division 4',
  '5' => 'Division 5',
);

$district_arr = array(
  '1' => 'District 1',
  '2' => 'District 2',
  '3' => 'District 3',
  '4' => 'District 4',
  '5' => 'District 5',
);

$thana_arr = array(
  '1' => 'Thana 1',
  '2' => 'Thana 2',
  '3' => 'Thana 3',
  '4' => 'Thana 4',
  '5' => 'Thana 5',
);

Then assign these three array to three options in $element as follows:

 $element['custom_select_field']['division'] = array(
   ....
   ....
   '#options' => $division_arr,
 );

$element['custom_select_field']['district'] = array(
   ....
   ....
   '#options' => $district_arr,
 );

$element['custom_select_field']['thana'] = array(
   ....
   ....
   '#options' => $thana_arr,
 );

Then kept the javascript portion same as before. That worked for me.