By JohnWoltman on
I am using hook_element_info to create a reusable widget for other modules I'm developing. The widget has dropdowns (SELECT elements) that get their value from a database, based on selections in other dropdowns. However, I run into a lot of "illegal choice" messages when, for example, clicking the "Preview" button (when I use the widget in a node form).
I think I'm just missing something in my #process function. The only functions I am implementing that the hook_element_info docs mention is the #process function that takes $element, $form_state, and $complete_form.
function city_chooser_form_process($element, &$form_state, $complete_form) {
// states
$options = array('A' => 'Alabama', 'N' => 'New Hampshire', 'C' => 'Colorado');
$element['sc_container']['existing_site_fields']['existing_state']['#options'] = $options;
// radio box
if ( !empty($form_state['values']['existing_or_new_site']) ) {
$element['sc_container']['existing_or_new_site']['#default_value'] = $form_state['values']['existing_or_new_site'];
}
$state = null;
if ( !empty($form_state['values']['existing_state']) ){
$element['sc_container']['existing_site_fields']['existing_state']['#default_value'] = $form_state['values']['existing_state'];
$state = $form_state['values']['existing_state'];
}
if ( triggered_by($form_state, 'existing_state') ) {
$state = $form_state['triggering_element']['#value'];
drupal_set_message('Triggered by existing_state, got value of <strong>'.$state.'</strong>', 'status');
}
// If there's a state and it's 'C', populate the list with Colorado cities.
if ( $state != null && $state == 'C' ) {
$element['sc_container']['existing_site_fields']['existing_city']['#options'] = array('d' => 'Denver', 's' => 'Saratoga', 'g' => 'Guthriesville');
}
else {
$element['sc_container']['existing_site_fields']['existing_city']['#options'] = array('Fictional Town 1', 'Fictional Town 2');
}
if ( !empty($form_state['values']['existing_city']) ) {
$element['sc_container']['existing_site_fields']['existing_city']['#default_value'] = $form_state['values']['existing_city'];
}
if ( triggered_by($form_state, 'existing_state') ) {
$form_state['rebuild'] = TRUE;
}
return $element;
}
Comments
Images for illustration
I've uploaded some images to illustrate the problem I'm having. It's very bizarre, so I hope the screenshots help.
Step 1 - Choose "Colorado": AJAX modifies the contents of the cities dropdown.
Step 2 - Click "Preview" button: Illegal choice message. State says the same (Colorado) but the Cities list is reset.
Step 3 - Click "Preview" button again: No illegal choice message, Cities list is correct but the selected city has been reset.
Code for illustration
I've cleaned up and posted code if that helps. I'm still working on it, and can't figure it out so far.
Official documentation didn't help
I've read http://drupal.org/node/752056, which I was hoping would shed some light, but it didn't explain it. I rewrote my code from scratch, using Examples as a base, but it still gives me the "illegal choice" message.
You can't use AJAX in Drupal
You can't use AJAX in Drupal forms like you do with regular forms. If any form elements are present in the submitted data that weren't part of the original form, Drupal gives the error you are getting. It's part of Drupal's form security.
You will need to use AHAH to do what you want.
Contact me to contract me for D7 -> D10/11 migrations.
I thought D7 called it AJAX
I thought D7 called it AJAX instead of D6's AHAH, even though it works similar to D6. It returns HTML, not XML. The Examples module uses the D7's new #ajax element FAPI property, which replaced #ahah.
Here's relevant code from hook_element_info implementation so you can see what the elements are:
Sorry, I didn't notice it was
Sorry, I didn't notice it was D7. You can ignore my last post as it may be entirely wrong. Or it may be entirely correct - I haven't done any D7 module development yet so I really don't know one way or the other. I'm waiting until there is an official release before I start playing with it.
Contact me to contract me for D7 -> D10/11 migrations.
No worries; I'm still
No worries; I'm still searching for the answer. Using XDebug, it looks like the $form_state['values'] doesn't get properly filled out when clicking the node's "preview" or "save" buttons. This is puzzling. Is there a step I'm missing when manipulating the form in #process?
Related bug?
Perhaps this bug #756762: AJAX should follow same rules for whether to call drupal_rebuild_form() as non-AJAX submissions is related?Apparently not.