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:


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

mradcliffe’s picture

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.

mradcliffe’s picture

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

adf1969’s picture

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.

BenVercammen’s picture

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...

BenVercammen’s picture

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...

jbeuckm’s picture

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?

kitt2012’s picture

Gentlemen,

How's it going? Thought I'd pop a post on here to see if anybody looking into this back in May found a solution. I've used the multiselect widgit in config forms, but have run into a problem using my current ajax form.

Looking through here it seems it was a current issue last year.

I will be having a stumble through the multiselect code today.

Thank you for any input.

xK

kitt2012’s picture

Seems to me that the results will be saved through to a $_POST value if all the options are selected.

multielect.js attempts to do this on line 15. However as the button clicked is registered as an ajax button, this does not fire.

On further testing, if all the options are physically selected from the selected options side, and then an ajax button is clicked - all options are saved to $_POST.

Linking multiselect.js line 15 -19 to ajax clicked triggers in the FAPI, seems to me to be the key.

xK

Jarada’s picture

In case anyone comes across this anew and wishes to get this sorted, the key to this fix is to do this selection before the form is serialized, not after. So instead of using beforeSend, which comes after, we use beforeSerialize.

/**
 * Perform action prior to form serialization.
 */
Drupal.ajax.prototype.beforeSerialize = function (element, options) {
	// TODO :: watch out, this might override another module's functionality...
	jQuery('select.multiselect_sel').selectAll();
}

In order to not override another module's functionality, I used this code (was working on preview, but you can adjust to work on other submits)...

(function ($) {
    Drupal.behaviors.MyPreviewMultiSelect = {
        attach: function (context, settings) {
            // 'edit-preview' is the element ID where you execute the #ajax.
            Drupal.ajax['edit-preview'].options.beforeSerialize = function (element_settings, options) {
                // When preview is clicked, ensure we have all the multiselect's selected
                jQuery('select.multiselect_sel').selectAll();
            }
        }
    };
})(jQuery);