in packages/react/src/components/ComboBox/ComboBox.tsx [948:1062]
private _setSelectedIndex(
index: number,
submitPendingValueEvent: React.SyntheticEvent<any>,
searchDirection: SearchDirection = SearchDirection.none,
): void {
const {
onChange,
onPendingValueChanged,
hoisted: { selectedIndices: initialIndices, currentOptions },
} = this.props;
// Clone currentOptions and selectedIndices so we don't mutate state
let selectedIndices = initialIndices ? initialIndices.slice() : [];
let changedOptions = currentOptions.slice();
// Find the next selectable index, if searchDirection is none
// we will get our starting index back
index = this._getNextSelectableIndex(index, searchDirection);
if (!indexWithinBounds(currentOptions, index)) {
return;
}
// Are we at a new index? If so, update the state, otherwise
// there is nothing to do
if (
this.props.multiSelect ||
selectedIndices.length < 1 ||
(selectedIndices.length === 1 && selectedIndices[0] !== index)
) {
const option: IComboBoxOption = { ...currentOptions[index] };
// if option doesn't existing, or option is disabled, we noop
if (!option || option.disabled) {
return;
}
if (this.props.multiSelect) {
// Setting the initial state of option.selected in Multi-select combo box by checking the
// selectedIndices array and overriding the undefined issue
option.selected = option.selected !== undefined ? !option.selected : selectedIndices.indexOf(index) < 0;
// handle changing all options if SelectAll is changed
if (option.itemType === SelectableOptionMenuItemType.SelectAll) {
selectedIndices = [];
// if select all is set to checked, push all selectable option indices
if (option.selected) {
currentOptions.forEach((currentOption, i) => {
if (!currentOption.disabled && isSelectableOption(currentOption)) {
selectedIndices.push(i);
changedOptions[i] = { ...currentOption, selected: true };
}
});
}
// otherwise un-check all options
else {
changedOptions = currentOptions.map(currentOption => ({ ...currentOption, selected: false }));
}
}
// otherwise update the individual option
else {
if (option.selected && selectedIndices.indexOf(index) < 0) {
selectedIndices.push(index);
} else if (!option.selected && selectedIndices.indexOf(index) >= 0) {
selectedIndices = selectedIndices.filter((value: number) => value !== index);
}
changedOptions[index] = option;
// If SelectAll exists and another option was toggled, update the SelectAll option's state
const selectAllOption = changedOptions.filter(o => o.itemType === SelectableOptionMenuItemType.SelectAll)[0];
if (selectAllOption) {
const selectAllState = this._isSelectAllChecked(selectedIndices);
const selectAllIndex = changedOptions.indexOf(selectAllOption);
if (selectAllState) {
selectedIndices.push(selectAllIndex);
changedOptions[selectAllIndex] = { ...selectAllOption, selected: true };
} else {
selectedIndices = selectedIndices.filter((value: number) => value !== selectAllIndex);
changedOptions[selectAllIndex] = { ...selectAllOption, selected: false };
}
}
}
} else {
selectedIndices[0] = index;
}
submitPendingValueEvent.persist();
// Only setState if combo box is uncontrolled.
if (this.props.selectedKey || this.props.selectedKey === null) {
// If combo box value is changed, revert preview first
if (this._hasPendingValue && onPendingValueChanged) {
onPendingValueChanged();
this._hasPendingValue = false;
}
} else {
this.props.hoisted.setSelectedIndices(selectedIndices);
this.props.hoisted.setCurrentOptions(changedOptions);
// If ComboBox value is changed, revert preview first
if (this._hasPendingValue && onPendingValueChanged) {
onPendingValueChanged();
this._hasPendingValue = false;
}
}
// Call onChange after state is updated
if (onChange) {
onChange(submitPendingValueEvent, option, index, undefined);
}
}
if (this.props.multiSelect && this.state.isOpen) {
return;
}
// clear all of the pending info
this._clearPendingInfo();
}