3

我正在开发一个权限系统,让用户控制谁可以访问/评论/编辑资源,就像您可以在 Google Drive 上找到的一样。我正在使用 React-Select multi 让资源所有者选择他想要授予资源访问权限的用户。

当我单击 react-select 显示的选项时,我希望将此选项添加到我的允许用户列表(由另一个组件处理的列表)中。这部分有效,我只是在 select 上使用了一个 onChange 处理程序(如您在下面的代码中所见)。

export default class AddUsersForm extends Component {

  PropTypes = {
    onSubmit: PropTypes.func.isRequired,
    usersList: PropTypes.array.isRequired, // List of all users in the company
    usersInPermissions: PropTypes.array.isRequired, // Users who already have access to the resource
  }

  handleChange(users){
    // Adds new user to the list of allowed users, an updated value for this.props.usersInPermissions will be received
    this.props.onSubmit(users);
  }

  render() {
    return (
      <form>
        <Select
          name="users"
          multi={true}
          options={this.props.usersList.filter(user => !this.props.usersInPermissions.includes(user.id))}
          onChange={(users) => this.handleChange(users)}
        />
      </form>
    );
  }

}

这就是我卡住的地方:一旦添加了选项,我想继续显示用户在文本字段中搜索第一个选项时可能使用的过滤器。它现在的工作方式,过滤器被删除,所有选项都显示在下拉列表中。

有什么简单的方法可以通过 React-Select 实现这一点吗?

非常感谢!

4

2 回答 2

1

此代码正在运行。也许有更好的方法。

// ManageUsers
import React, { PropTypes } from 'react';
import AddUserForm from './AddUserForm'

export default class NoMatch extends React.Component {
  constructor(props) {
    super(props)
    this.handleChange = this.handleChange.bind(this);

    let selectedUsers = [ { value: 3, label: 'Three' },
      { value: 4, label: 'Four' } ];

    this.state = {
      selectedUsers: selectedUsers
    }
  }

  handleChange(selected) {
    this.setState({ selectedUsers: selected })
  }

  render() {
    let usersList = [
      { value: 1, label: 'One' },
      { value: 2, label: 'Two' }
    ];

    return (
      <div>Users
        <AddUserForm usersList={usersList} 
         selectedUsers={this.state.selectedUsers} 
         handleChange={this.handleChange} />
      </div>
    );
  }
}
// AddUsersForm
import React, { PropTypes } from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';

export default class AddUsersForm extends React.Component {
 PropTypes = {
  usersList: PropTypes.array.isRequired,
  selectedUsers: PropTypes.array.isRequired,
  handleChange: PropTypes.func.isRequired
 }

 render() {
  return (
   <form>
    <Select
     multi={true}
     options={this.props.usersList}
     value={this.props.selectedUsers}
     onChange={(users) => this.props.handleChange(users)}
    />
   </form>
  );
 }
}

如果要保留键入的文本,则必须在 handleChange 上设置输入文本。没有内置函数来保留键入的文本。

在此处输入图像描述

 onChange={(users) => this.props.handleChange(users, event)}
handleChange(selected, event) {
let selectedFilter = event.target;
 // then navigated to the input element with Javascript or jQuery
 // and set the value of the input

this.setState({ selectedUsers: selected })
}
于 2017-04-20T17:12:20.453 回答
1

我的方式:

  1. 用自己的组件替换Option了组件(来自 Material-UI 库的几个组件)。
  2. 重写的事件处理程序 - 这是来自 ReactSelect 道具onClick的一些逻辑和调用处理程序。onChangeonClick处理程序的末尾添加event.stopPropagation()
import React from 'react';

import MenuItem from '@material-ui/core/MenuItem/MenuItem';
import Checkbox from '@material-ui/core/Checkbox/Checkbox';
import ListItemText from '@material-ui/core/ListItemText/ListItemText';

const MultiOption = props => (
  <MenuItem
    buttonRef={props.innerRef}
    {...props.innerProps}
    onClick={event => {
      let values = [];
      if (props.isSelected) {
        values = props.selectProps.value.filter(
          item => item.value !== props.value,
        );
      } else {
        values = [props.data].concat(props.selectProps.value);
      }
      props.selectProps.onChange(values);
      event.stopPropagation();
    }}
    style={{
      overflow: 'initial',
      padding: 0,
    }}
  >
    <Checkbox
      checked={props.isSelected}
      style={{
        padding: 4,
      }}
    />
    <ListItemText
      primary={props.label}
      classes={{
        root: props.selectProps.classes.optionRoot,
      }}
    />
  </MenuItem>
);

export default MultiOption;
import React from 'react';
import PropTypes from 'prop-types';
import Select from 'react-select';

import { withStyles } from '@material-ui/core/styles';

import { getComponents } from './components';

import { styles, getSelectStyles } from './styles';

class Combobox extends React.Component {
  handleChange = () => value => {
    const { onChange } = this.props;
    onChange(value);
  };

  render() {
    const {
      classes,
      theme,
      options,
      label,
      rootStyle,
      value,
      error,
      isInner,
      isMulti,
      fullWidth,
      ...props
    } = this.props;

    return (
      <div className={classes.root} style={{ ...rootStyle }}>
        <Select
          {...props}
          isClearable
          classes={classes}
          styles={getSelectStyles({
            theme,
            fullWidth,
          })}
          options={options}
          menuPortalTarget={document.body}
          menuPlacement="auto"
          value={value || null}
          onChange={this.handleChange()}
          components={getComponents({
            isInner,
            isMulti,
          })}
          textFieldProps={{
            label,
            error: !!error,
            helperText: error,
            InputLabelProps: { shrink: true },
          }}
          isMulti={isMulti}
          hideSelectedOptions={!isMulti}
          closeMenuOnSelect={!isMulti}
          loadingMessage={() => 'Loading...'}
        />
      </div>
    );
  }
}

Combobox.propTypes = {
  options: PropTypes.arrayOf(PropTypes.shape({})),
  label: PropTypes.string,
  classes: PropTypes.shape({}).isRequired,
  theme: PropTypes.shape({}).isRequired,
  value: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.bool,
    PropTypes.arrayOf(PropTypes.any),
    PropTypes.shape({}),
  ]),
  error: PropTypes.string,
  onChange: PropTypes.func.isRequired,
  isInner: PropTypes.bool,
  isMulti: PropTypes.bool,
  fullWidth: PropTypes.bool,
};

Combobox.defaultProps = {
  options: [],
  label: '',
  value: null,
  error: '',
  isInner: false,
  isMulti: false,
  fullWidth: false,
};

export default withStyles(styles, { withTheme: true })(({ ...props }) => (
  <Combobox {...props} />
));
import Control from './Control';
import InnerControl from './InnerControl';

import InputComponent from './InputComponent';
import MenuList from './MenuList';

import Option from './Option';
import MultiOption from './MultiOption';

import SingleValue from './SingleValue';
import MultiValue from './MultiValue';

import NoOptionsMessage from './NoOptionsMessage';

import Placeholder from './Placeholder';

import ValueContainer from './ValueContainer';

const getComponents = ({ isInner, isMulti }) => ({
  Control: isInner ? InnerControl : Control,
  ...(isMulti && { MenuList }),
  MultiValue,
  NoOptionsMessage,
  Option: isMulti ? MultiOption : Option,
  Placeholder,
  SingleValue,
  ValueContainer,
});

export {
  Control,
  InnerControl,
  InputComponent,
  MenuList,
  Option,
  MultiOption,
  SingleValue,
  MultiValue,
  NoOptionsMessage,
  Placeholder,
  ValueContainer,
  getComponents,
};
于 2019-01-17T14:22:08.687 回答