Download & Extend

Changing multiselect options using #ajax

Project:Multiselect
Version:7.x-1.x-dev
Component:Code
Category:support request
Priority:normal
Assigned:Unassigned
Status:active

Issue Summary

Using the new D7 AJAX form API stuff I'm trying to rebuild the multiselect options on the fly with AJAX.

I can see that $options is indeed being changed so I know that Drupal FAPI is doing what it needs to update $form_state. However, the form options actually don't change. I am not familiar enough with multiselect to understand if it is processing $form_state or doing anything funky with the $options.

Any ideas to point me in the right direction? Hopefully it's not a bug and it's possible to do with multiselect...

This is a crude example:

<?php
function my_form($form, &$form_state) {
 
$form['blah'] = array(
   
'#type' => 'select',
   
'#title' => t('Blah'),
   
'#options' => array(1 => '1', 2 => '2'),
   
'#ajax' => array(
     
'callback' => 'my_callback',
     
'wrapper' => 'multiselect',
    ),
  );

 
$options = (isset($form_state['values']['blah']) && $form_state['values']['blah'] == 2) ? array('one' => 'One', 'two' => 'Two') : array('yes' => 'Yes', 'no' => 'No');
 
$form['other'] = array(
   
'#type' => 'multiselect',
   
'#title' => t('Other'),
   
'#prefix' => '<div id="multiselect">',
   
'#suffix' => '</div>',
   
'#options' => $options,
  );

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

  return
$form;
}

function
my_callback($form, &$form_state) {
  return
$form['other'];
}

function
my_form_submit($form, &$form_state) {

}
?>

Comments

#1

Status:active» closed (cannot reproduce)

I'm going to close this for now as I just tried with a normal select list, and I had the same issue.

I'm sorry for the spam.

#2

I confirmed it working with a very simple form. Sorry for the spam again.

#3

Status:closed (cannot reproduce)» active

@mradcliffe:

You are not nuts or wrong.
I just tried it with standard "select" and it works fine.
If I change the widget to a multiselect it doesn't work (version: dev-2011-03-07)

The problem is that when the callback is processed (from a button-click or any other AJAX request) it doesn't send back the values in the 2 multiselect select boxes.

If I can find the time, I'll dive into the multiselect code and see if I can figure out why it isn't sending the values back with the POST.

Andrew.

#4

I'm currently facing the same issue, I don't get the values that are selected in the multiselect field when performing an AJAX callback triggered by another field.

As I was digging into the code, I figured out that only the "selected" items in the multiselect box are submitted. I also discovered that when submitting the form, the field will automatically select all options in the "_sel" box via $('select.multiselect_sel').selectAll().

So the only missing link here is that before relying on the selected data in your AJAX callback, you'll need to trigger the selectAll() code so all values are being put in your $_POST data. Otherwise they'll never end up in your $form_state['values'].

I'm still stuck on this last part, as I'm not sure which place is the best to trigger the selectAll function...

#5

Okay, I've found a rather nice and clean way to solve the issue... I've added the following lines to the multiselect.js script:

/**
* Modify form values prior to form submission.
*/
Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
// TODO :: watch out, this might override another module's functionality...
jQuery('select.multiselect_sel').selectAll();
}

I'm not sure whether this can override or be overridden by other modules implementing this function. To make sure we don't override, we could put the callback in a variable and call it in our new function, which could look something like this:

$originalSuccess = Drupal.ajax.prototype.success;
$modifiedSuccess = (function($response, $status){
$originalSuccess($response, $status);
// Additional code here...
});
Drupal.ajax.prototype.success = $modifiedSuccess;

One final obstacle (which is more just a matter of aesthetics) is to "deselect" all items when loading the page again, but I've already spent enough time on this for now...

#6

I see why this should work, but I added the beforeSubmit code above to my module and $form_state['values']['multiselect_element'] is still NULL.

This is my module's behavior code that submits the form when add/remove buttons are pressed:

  $('.multiselect_btns', context).find('a').click(function(){
    $('select.multiselect_sel').selectAll();
    $('#multiselect-submitter', context).change();
  });

Here is the element that makes the AJAX call:

'multiselect-submitter' => array(
'#type' => 'select',
'#prefix' => '<div id="multiselect-submitter-holder" style="display:none;">',
'#suffix' => '</div>',
'#id' => 'multiselect-submitter',
'#ajax' => array(
'callback' => 'ajax_save_multiselect_settings',
'wrapper' => 'multiselect-submitter-holder',
),
),

I even modified the AJAX behavior code so that I could verify that the multiselect_sel elements had their options selected:

Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
  // TODO :: watch out, this might override another module's functionality...
  jQuery('select.multiselect_sel').selectAll();

  jQuery('select.multiselect_sel').each(function(){
    alert('submitting '+jQuery(this).val());
  });

}

The alert reports null when an item is added and reports the option value when one is removed (ironically close to the opposite of what I want). I have tried moving my module's weight ahead and behind the multiselect module with the same results. How can I get my current values on AJAX?

nobody click here