replace behavior not working with item form elements
| Project: | AHAH helper |
| Version: | 6.x-1.0 |
| Component: | Code |
| Category: | support request |
| Priority: | normal |
| Assigned: | Wim Leers |
| Status: | postponed (maintainer needs more info) |
Jump to:
I have a form to create an ingestion, for a diet module I'm working on. An ingestion is a group of meals (first course, second, drinks....) and I use the ahah helper module to build up a meal list subform within the ingestion form. It works great as long as I use textfields elements for the list of meals (I use the replace behavior to update the list with a new meal chosen with an autocomplete field). However, it would be great to have a list of items elements instead of textfields elements, because once a meal is chosen and added to the list I don't want the user to be able to change it (only delete). But the ahah is not working if I change the textfield element for an item element. Even if I set the meal textfield as disabled the ahah fails. Is there any structural reason, in the ahah helper module, for that?

#1
The actual question is this part:
So you are changing
#type, right?Basically something like:
$form['something'] = array('#type' => ($some_state_or_value_is_set) ? 'item' : 'textfield',
// …
'#value' => ($some_state_or_value_is_set) ? $the_value : NULL,
// …
);
Right? I don't know by heart why this wouldn't work. Could you maybe post a piece of sample code? Then I could start working and potentially debugging from that.
#2
this is the menu entry:
$items['diet/ingestion/%node/meal/add'] = array('title' => 'Add a meal to an ingestion',
'page callback' => 'drupal_get_form',
'page arguments' => array('diet_ingestion_meal_add', 2),
//'access callback' => true,
'access callback' => 'node_access',
'access arguments' => array('update', 2),
'type' => MENU_CALLBACK,
//'file' => drupal_get_path('modules', 'diet') . '/includes/diet.ingestion.inc',
);
and this is the callback function to build up the form:
function diet_ingestion_meal_add($form_state, $node) {
$form['nid'] = array('#type' => 'hidden', '#value' => $node->nid);
$form['meal_list'] = _diet_meal_list_subform($form_state);
$form['add_meal'] = _diet_add_meal_subform();
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Add meals'),
);
return $form;
}
These are the helpers functions for the previous callback function:
function _diet_meal_list_subform($form_state) {
$form = array(
'#type' => 'fieldset',
'#title' => t('Meals'),
'#prefix' => '<div id="meal-list-wrapper">',
'#suffix' => '</div>',
'#tree' => TRUE,
);
$submitted_values = (($form_state['values']['mname'] != '') && $form_state['clicked_button']['#value'] != t('Delete meal')) ? true : false;
$i = 0;
// This will only be printed if at least two meals have been added
if (is_array($form_state['values']['meal_list'][0]) || !$form_state['submitted']){
//unset meals if its delete meal button has been clicked
foreach ($form_state['values']['meal_list'] as $key => $value) {
if($form_state['clicked_button']['#post']['del_' .$key]) {
unset($form_state['values']['meal_list'][$key]);
unset($form_state['storage']["#existing_form_items"]['meal_list'][$key]);
}
}
foreach ($form_state['values']['meal_list'] as $key => $value) {
$form[$key] = array(
'#type' => 'item',
'#theme' => 'diet_new_meal_element',
);
$form[$key]['m'] = array(
'#type' => 'textfield',
'#title' => t('Meal'),
'#size' => 40,
'#value' => $form_state['values']['meal_list'][$key]['m'],
'#theme' => 'diet_meal_element_text',
);
$form[$key]['delete_meal'] = array(
'#type' => 'button',
'#value' => t('Delete meal'),
'#name' => 'del_' . $key,
);
}
}
//print the last meal added
if ($submitted_values && !$form_state['submitted']) {
$i = $key + 1;
$form[$i] = array(
'#type' => 'item',
'#theme' => 'diet_new_meal_element',
);
$form[$i]['m'] = array(
'#type' => 'textfield',
'#title' => t('Meal'),
'#size' => 40,
'#value' => $form_state['values']['mname'],
'#theme' => 'diet_meal_element_text',
);
$form[$i]['delete_meal'] = array(
'#type' => 'button',
'#value' => t('Delete meal'),
'#name' => 'del_' . $i,
);
}
return $form;
}
function _diet_add_meal_subform() {
$form = array(
'#type' => 'fieldset',
'#title' => t('Add a meal'),
'#collapsible' => false,
);
$form['mname'] = array(
'#type' => 'textfield',
'#title' => t('Meal'),
'#size' => 40,
'#autocomplete_path' => 'diet/autocomplete/meal',
'#default_value' => '',
);
$form['add_meal'] = array(
'#type' => 'submit',
'#value' => t('Add meal'),
'#name' => 'add_meal',
'#ahah' => array(
'path' => ahah_helper_path(array('meal_list')),
'wrapper' => 'meal-list-wrapper',
'method' => 'replace',
'effect' => 'fade',
),
);
return $form;
}
I'm sure this code could be better but this is actually working. And indeed, by only changing the type of the element $form[$key]['m'] to item the list doesn't work. What I've seen is that ,when doing that change, the element $form_state['values']['meal_list'] doesn't get posted, thus the if section
if (is_array($form_state['values']['meal_list'][0]) || !$form_state['submitted']){doesn't get printed. Then, only the last meal is been shown in the list.
Can you see what's wrong? thanks very much for your help.
#3
More over: I use a theme function, based on theme_texfield, to show an element in the list in different ways:
function theme_diet_meal_element_text($element) {
$size = empty($element['#size']) ? '' : ' size="'. $element['#size'] .'"';
$maxlength = empty($element['#maxlength']) ? '' : ' maxlength="'. $element['#maxlength'] .'"';
$class = array('form-text');
$extra = '';
$output = '';
if ($element['#autocomplete_path'] && menu_valid_path(array('link_path' => $element['#autocomplete_path']))) {
drupal_add_js('misc/autocomplete.js');
$class[] = 'form-autocomplete';
$extra = '<input class="autocomplete" type="hidden" id="'. $element['#id'] .'-autocomplete" value="'. check_url(url($element['#autocomplete_path'], array('absolute' => TRUE))) .'" disabled="disabled" />';
}
_form_set_class($element, $class);
if (isset($element['#field_prefix'])) {
$output .= '<span class="field-prefix">'. $element['#field_prefix'] .'</span> ';
}
//---> 3 lines to comment/uncomment to display a different form item.
//$output .= check_plain($element['#value']);
$output .= '<input type="text"'. $maxlength .' name="'. $element['#name'] .'" id="'. $element['#id'] .'"'. $size .' value="'. check_plain($element['#value']) .'"'. drupal_attributes($element['#attributes']) .' />';
//$output .= '<input type="text"'. $maxlength .' name="'. $element['#name'] .'" id="'. $element['#id'] .'"'. $size .' value="'. check_plain($element['#value']) .'"'. drupal_attributes($element['#attributes']) .'" disabled="disabled" />';
if (isset($element['#field_suffix'])) {
$output .= ' <span class="field-suffix">'. $element['#field_suffix'] .'</span>';
}
return theme('form_element', $element, $output) . $extra;
}
There are three lines which allow you to show the item in three different ways:
....//---> 3 lines to comment/uncomment to display a different form item.
//$output .= check_plain($element['#value']);
$output .= '<input type="text"'. $maxlength .' name="'. $element['#name'] .'" id="'. $element['#id'] .'"'. $size .' value="'. check_plain($element['#value']) .'"'. drupal_attributes($element['#attributes']) .' />';
//$output .= '<input type="text"'. $maxlength .' name="'. $element['#name'] .'" id="'. $element['#id'] .'"'. $size .' value="'. check_plain($element['#value']) .'"'. drupal_attributes($element['#attributes']) .'" disabled="disabled" />';
....
Whenever you choose to show only the element value or a disabled textfield the meals list only show the last element.
#4
Please update to version 2 and check if this problem persists.