score:0

I kind of found one solution to deal with it on my own, after fiddling through documentation for some unrelated Problem. The solution includes

  1. Setting value = {[...myStateVariable]}
  2. Using the reason parameter from the onChange((event, newValue, reason)=>{....}) callback
            <Autocomplete
                multiple
                id="tags-outlined"
                options={students}
                getOptionLabel={(option) => option.personalInfo.firstName+' '+option.personalInfo.lastName}
                defaultValue={[...added]}
                value={[...added]}
                onChange={(e, newVal, reason)=>{

                    if(reason==="select-option"){
                        addChips(newVal)
                    } else if(reason==="remove-option"){
                        handleDelete(newVal)
                    }
                }}

The HandleDelete and addChips method are as follows.

    const [added, setAdded] = useState([...added2])

    const handleDelete = (students)=>{
        setAdded([...students])
    }

    const addChips = (students)=>{
        if(added.length>= maxParticipation){
            alert('Cannot add more participants')
        }else{
            setAdded([...students])
        }
    }

the 'newValue' is first intercepted by the 'onChange' callback where it's length is evaluated and if the length is greater than a limiting value, the value update is cancelled. (Notice, the onChange that causes abortion of the process is only the one where "reason" = 'select-option' ). P.S- (forgot to mention about the disable Options query) the "disable" attribute on Options could also be manipulated in the renderOptions to disable all the options after "newVal" reaches a given length. [ solution for that(disable options) given in detail by @justindra ]

score:0

I used slice to limit the maximum limit on renderTags before rendering the chips

<Autocomplete
  renderTags={(options, getTagProps) =>
    options.slice(0, 5).map((option) => (
      <Chip
        icon={
          <FaceIcon /> /*<Avatar color="primary" variant='outlined' size="small" className={classes.small}></Avatar>*/
        }
        label={option.personalInfo.firstName + ' ' + option.personalInfo.lastName}
        color="primary"
        variant="outlined"
        {...getTagProps({})}
      />
    ))
  }
/>

score:0

 <Autocomplete
                  multiple
                  id="role"
                  options={rootStore.roleStore.listRole}
                  disableCloseOnSelect
                  value={rootStore.userStore.user.role}
                  onChange={(event, newValue) => {
                    setErrors({
                      ...errors,
                      role: Utils.validate.single(
                        newValue,
                        Utils.constraintsUser.role
                      ),
                    })
                    if (newValue.length > 2) {
                      alert("Please select max 2 labs")
                    } else {
                      rootStore.userStore.updateUser({
                        ...rootStore.userStore.user,
                        role: newValue,
                      })
                    }
                  }}
                  getOptionLabel={(option) => option.description || ""}
                  renderOption={(option, { selected }) => (
                    <React.Fragment>
                      <Checkbox style={{ marginRight: 8 }} checked={selected} />
                      {option.description}
                    </React.Fragment>
                  )}
                  renderInput={(params) => (
                    <TextField
                      {...params}
                      variant="outlined"
                      label="Labs"
                      placeholder="Labs"
                    />
                  )}
                />

perfect solution..

score:0

My solution,I think it's the most properly way:

<Autocomplete
  value={selectedTags}
  onChange={(ev, value: Tag[]) => {
    if (value.length <= 3) {
      setSelectedTags(value);
    } else {
      return;
    }
  }}
/>;

score:0

In my case, this worked fine.

onChange={(e, newVal) => {
    if (newVal > 3) {
      newVal.pop(); 
    }
    setAdded([...newVal]);
}

Though the documentation explains that the value parameter of onChange prop is the new value, the actual content seems the array of all selected options.

And the last element in the value array is the newly selected option by the current change event. Therefore the code snippet above eliminates the exceeding element against the limited number (3 as above).

The latter type (Array<T>) for value parameter in the documentation is the case.

score:1

Autocomplete added getOptionDisabled prop that can be used to disable all non selected options after maximum number of options is selected.

const a = ({limit = 3})=> {
    const [limitReached, setLimitReached] = useState(false);
    const [values, setValues] = useState([]);
    const onSelect = useCallback((newValues) => {
        setValues(newValues);
        setLimitReached(newValues.length >= limit);
    }, [limit]);


  const checkDisable = useCallback(option => limitReached && !values.includes(option), [limitReached, values]);

  return <Autocomplete
                getOptionDisabled={checkDisable}
                multiple
                onChange={onSelect}
                options={options}
                value={values}
            />
}

score:2

Ran into similar issue recently. This is what I ended up doing. Basically you have to set the disabled flag on the chip itself directly, so it disables the text input, but not the chip. So you can still delete each chip.

export const AutoCompleteWithLimit: React.FC<Props> = ({
  disabled = false,
  limit = 2,
}) => {
  const [disableInput, setDisableInput] = useState<boolean>(
    value.length >= limit
  );

  return (
    <Autocomplete
      // Set disabled based on input
      disabled={disabled || disableInput}
      multiple
      renderTags={(tagValue, getTagProps) =>
        tagValue.map((option, index) => (
          <Chip
            key={index}
            label={option.name}
            {...getTagProps({ index })}
            // Set disable explicitly after getTagProps
            disabled={disabled}
          />
        ))
      }
      onChange={(_event: any, newValue: any[]) => {
        // do something else
        // set the disable input
        setDisableInput(newValue.length >= limit);
      }}
    />
  );
};

Related Query

More Query from same tag