breq
breq

Reputation: 25516

Material-UI Autocomplete onChange not updates value

I want to use onChange event on Autocomplete component to get current selected values. The problem is that it does not working as expected, so when I click to check/uncheck value checkbox is still unchecked but in console i can see that new value was added

uncoment this part to make it works:

  value={myTempVal}
      onChange={(event, newValue) => {
        setMyTempVal(newValue);
        console.log(newValue);
      }}

online demo: https://codesandbox.io/embed/hardcore-snowflake-7chnc?fontsize=14&hidenavigation=1&theme=dark

code:

const [myTempVal, setMyTempVal] = React.useState([]);

<Autocomplete
      open
      multiple
      value={myTempVal}
      onChange={(event, newValue) => {
        setMyTempVal(newValue);
        console.log(newValue);
      }}
      disableCloseOnSelect
      disablePortal
      renderTags={() => null}
      noOptionsText="No labels"
      renderOption={(option, { selected }) => {
        return (
          <>
            <Checkbox
              icon={icon}
              checkedIcon={checkedIcon}
              style={{ marginRight: 8 }}
              checked={selected}
            />
            {option.title}
          </>
        );
      }}
      options={option2}
      // groupBy={option => option.groupName}
      getOptionLabel={option => option.title}
      renderInput={params => (
        <div>
          <div>
            <SearchIcon />
          </div>
          <TextField
            variant="outlined"
            fullWidth
            ref={params.InputProps.ref}
            inputProps={params.inputProps}
          />
        </div>
      )}
    />

Upvotes: 0

Views: 9697

Answers (3)

Sandeep
Sandeep

Reputation: 141

It is bit late to Answer this question but it might help someone.

In your code you have added onChange event in Autocomplete. When you click on checkbox it will trigger 2 times, one for checkbox and one for Autocomplte. Hence 2nd time trigger makes again checkbox unchecked so u get value in console but still checkbox is empty.

You can remove your checkbox in renderOption and use checked and uncheked icon instaed of checkbox.

renderOption={(option, { selected }) => {
        return (
           <React.Fragment>
            {selected ? <CheckedIcon> : <uncheckedIcon>}
            <div>
            {option.title}
            </div>
           </React.Fragment>
          </>
        );
      }}

Upvotes: 0

Anis Smail
Anis Smail

Reputation: 779

You need to get donors receivers and options variables out of the function. Those variables get re-created at each render, this means that their reference changes at each render, and as Autocomplete makes a reference equality check to decide if an option is selected he never finds the options selected.

const donors = [...new Set(data.map(row => row.donor))].map(row => {
  return {
    groupName: "Donors",
    type: "donor",
    title: row || "null"
  };
});
const receivers = [...new Set(data.map(row => row.receiver))].map(row => {
  return {
    groupName: "Receivers",
    type: "receiver",
    title: row || "null"
  };
});
const option2 = [...donors, ...receivers];

export const App = props => {

  const [myTempVal, setMyTempVal] = React.useState([]);

  return (
    <Autocomplete
      open
      multiple
...

You can also add getOptionSelected to overwrite the reference check :

<Autocomplete
      open
      multiple
      disableCloseOnSelect
      disablePortal
      renderTags={() => null}
      noOptionsText="No labels"
      getOptionSelected={(option, value) => option.title === value.title} 
      renderOption={(option, { selected }) => {
        return (
          <>
            <Checkbox
              icon={icon}
              checkedIcon={checkedIcon}
              style={{ marginRight: 8 }}
              checked={selected}
            />
            {option.title}
          </>
        );
      }}
      options={option2}
      // groupBy={option => option.groupName}
      getOptionLabel={option => option.title}
      renderInput={params => (
        <div>
          <div>
            <SearchIcon />
          </div>
          <TextField
            variant="outlined"
            fullWidth
            ref={params.InputProps.ref}
            inputProps={params.inputProps}
          />
        </div>
      )}
    />

Upvotes: 1

Merci Dieu KIMPOLO
Merci Dieu KIMPOLO

Reputation: 443

This can help: Replace

checked={selected}

To

checked={myTempVal.filter(obj=>obj.title===option.title).length!==0}

The complete solution

import React from "react";
import "./styles.css";
import TextField from "@material-ui/core/TextField";
import Autocomplete from "@material-ui/lab/Autocomplete";
import CheckBoxOutlineBlankIcon from "@material-ui/icons/CheckBoxOutlineBlank";
import CheckBoxIcon from "@material-ui/icons/CheckBox";
import Checkbox from "@material-ui/core/Checkbox";
import SearchIcon from "@material-ui/icons/Search";

const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
const checkedIcon = <CheckBoxIcon fontSize="small" />;

const data = [
  { donor: "Trader Joe's", receiver: "Person-to-Person" },
  { donor: "Trader Joe's", receiver: "Homes with Hope" },
  { donor: "Santa Maria", receiver: "Gillespie Center" },
  { donor: "Santa Maria", receiver: null }
];

export const App = props => {
  const donors = [...new Set(data.map(row => row.donor))].map(row => {
    return {
      groupName: "Donors",
      type: "donor",
      title: row || "null"
    };
  });
  const receivers = [...new Set(data.map(row => row.receiver))].map(row => {
    return {
      groupName: "Receivers",
      type: "receiver",
      title: row || "null"
    };
  });
  const option2 = [...donors, ...receivers];

  const [myTempVal, setMyTempVal] = React.useState([]);

  return (
    <Autocomplete
      open
      multiple
      value={myTempVal}

      disableCloseOnSelect
      disablePortal
      renderTags={() => null}
      noOptionsText="No labels"
      renderOption={(option, { selected }) => {
        return (
          <>
            <Checkbox
            onClick={
              ()=>{
                if(myTempVal.filter(obj=>obj.title===option.title).length!==0){
                  setMyTempVal([...myTempVal.filter(obj=>obj.title!==option.title)],console.log(myTempVal))
                }else{
                  setMyTempVal([...myTempVal.filter(obj=>obj.title!==option.title),option],console.log(myTempVal))
                }

              }
            }
              icon={icon}
              checkedIcon={checkedIcon}
              style={{ marginRight: 8 }}
              checked={myTempVal.filter(obj=>obj.title===option.title).length!==0}
            />
            {option.title}
          </>
        );
      }}
      options={option2}
      // groupBy={option => option.groupName}
      getOptionLabel={option => option.title}
      renderInput={params => (
        <div>
          <div>
            <SearchIcon />
          </div>
          <TextField
            variant="outlined"
            fullWidth
            ref={params.InputProps.ref}
            inputProps={params.inputProps}
          />
        </div>
      )}
    />
  );
};
export default App;

Upvotes: 0

Related Questions