How do deselect a particular SELECT option in a multi-select
In Selenium individual options can be easily selected/deselect by clicking on them (even if SELECT itself isn't expanded). It even doesn't force you to do a Ctrl/CMD+Click on an option to append it to current selection. I haven't seen such luxury in other JavaScript enabled drivers (e.g. Sahi, Zombie), where the only method that allows to manipulate SELECT element is called setSelected (or similar) and accepts an array of option values to be selected.
Without individual option deselection the only possible way is to call NodeElement::selectOption method multiple times in following fashion:
$multi_select->selectOption('value1', true); // true - to reset selection to this option
$multi_select->selectOption('value2', false); // false - to append to current selection
$multi_select->selectOption('valueN', false); // false - to append to current selection
...
Having some sort of resetSelection method of a driver, that would uncheck all options would be a great help in this case.
Implementing such method however isn't that easy as it sounds, because native setSelected methods of underlying browser controllers:
- doesn't support selecting non-existing options just to unselect all of them
- doesn't support
setValue('')call on a multi-select just to unselect all options
Without changing DriverInterface and associated drivers I don't have any other choice for deselection an option, then:
- use
getValueto get currently selected options - remove options, that needs to be deselected from resulting array
- call
selectOptionmultiple times (see example in the beginning)
This approach has major drawback - multiple onchange event calls, that doesn't really happen when user himself is changing multi-select selection.
Any ideas would be appreciated.
Also deselecting last selected option might be bad idea, because it's impossible to call selectOption with a value that doesn't exist in a SELECT just to unselect all other options.
:+1: Just had the same issue, agree that only with a change of the driver interface and the drivers this issue could be solved. Would be nice if the driver were to offer some methods to manipulate the DOM/single nodes (add/remove/edit attributes)
@cgrossde Mink is meant to emulate the browser. Adding or removing attributes on DOM nodes is not something a browser let you do (the DevTools let you do that, not the interface of a normal browser user). So I'm totally against adding such method in our DriverInterface (thus, it might make things hard for BrowserKit's form handling for instance).
Btw, to deselect all options of a multi-select, ->setValue(array()) is supported now (it was maybe not in August 2013). Multi-select value is an array.
@aik099 using setValue() with the new selected options works now, which solves the issue of multiple change events.
The issue with your resetSelection is that it does not play well with single-select, where something is always selected
Thanks for the fast reply, I just tested it an this works for me:
UPDATE: Incorporated @stof 's hint from bellow
public function deselectOption($select, $option) {
$field = $this->getSession()->getPage()->findField($select);
if (null === $field) {
throw Behat\Mink\Exception('form field (select) :"'.$select.'" not found');
}
$values = $field->getValue();
if($values !== null && is_array($values)) {
// Array -> Multiselect -> check all values
for($i = 0; $i < count($values); $i++) {
// Remove our option from $values
if($values[$i] === $option) {
array_splice($values, $i, 1);
break;
}
}
$field->setValue($values);
}
}
@cgrossde your own code is triggering multiple change events. You should use $field->setValue($values) as the driver is then smart enough to trigger a single change event (or at least should be if it want to have passing tests)