private _setSelectedIndex()

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();
  }