Pranav
Pranav

Reputation: 1646

How to disable an option which is already selected from dropdown list?

In a React project using antd library, I've created a list of options from a json data which is populated as a drop-down list. Following is the code for reference

The json data

const newData = [
  {
    id: 123,
    name: "Vijay"
  },
  {
    id: 345,
    name: "Sanket"
  },
  {
    id: 546,
    name: "Hitesh"
  },
  {
    id: 789,
    name: "Sameer"
  },
  {
    id: 421,
    name: "Akshay"
  }
];

That data is used over here in <Select/>

<h2>Data 1</h2>
    <Select
      onChange={(key, val) => handleOnValuesChange(key, val)}
      placeholder="Select any one"
      style={{ width: 120 }}
      options={newData.map((_) => ({
        label: _.name,
        value: _.id
      }))}
      bordered={false}
    />
    <br />
    <h2>Data 2</h2>
    <Select
      onChange={(key, val) => handleOnValuesChange(key, val)}
      placeholder="Select any one"
      style={{ width: 120 }}
      options={newData.map((_) => ({
        label: _.name,
        value: _.id
      }))}
      bordered={false}
    />

The onChange function

const handleOnValuesChange = (key, val) => {
  const allData = newData.map((data) => {
    if (data.id === val) {
      return {
        ...data,
        disabled: true
      };
    } else {
      return {
        ...data,
        disabled: false
      };
    }
  });
  console.log("NEW DATA", allData);
};

When Vijay and Akshay is selected, I'am expecting the data as

0: {id: 1, value: "Vijay", disabled: true } 
1: {id: 2, value: "Sanket", disabled: false}
2: {id: 3, value: "Hitesh", disabled: false }
3: {id: 4, value: "Sameer", disabled: false }
4: {id: 5, value: "Akshay", disabled: true }

but getting output as

0: {id: 1, value: "Vijay", disabled: false } {/* This disabled should change to true */}
1: {id: 2, value: "Sanket", disabled: false}
2: {id: 3, value: "Hitesh", disabled: false }
3: {id: 4, value: "Sameer", disabled: false }
4: {id: 5, value: "Akshay", disabled: true }

How to tackle this? Any appropriate solution highly appreciated

This is the codesandbox link as: https://codesandbox.io/s/bordered-less-antd-4-17-0-alpha-7-forked-wtur0

Upvotes: 1

Views: 1527

Answers (3)

theinfiltrator
theinfiltrator

Reputation: 91

The newData should be stored in a state inorder to achieve disabling of options already selected. This is because the DOM gets re-rendered only if props or state is updated.

So in your code since the data is not stored in any state it does not change the non focused option, once the focused option is changed.

I have made some changes to the code and added the working example in sandbox.

  const [data, setData] = React.useState(updatedData); //store the newData with disabled added
  const [prevKey, setPrevKey] = React.useState(null); //store the last changed option



  const handleOnValuesChange = (key, val) => {
    const updating = [...data];
    setPrevKey(val.value);
    data.map((d, i) => {
      if (d.id === val.value) {
        updating[i] = {
          ...d,
          disabled: true
        };
      }
      if (d.id === prevKey) { //this toggles the previous selected value to false
        updating[i] = {
          ...d,
          disabled: false
        };
      }
    });
    setData(updating);
  };



.....
<Select
        onChange={(key, val) => handleOnValuesChange(key, val)}
        placeholder="Select any one"
        style={{ width: 120 }}
        options={data
          .filter((d) => d.disabled === false) //this shows only the options that are not disabled
          .map((_) => {
          console.log(_.name)
          console.log(_.id)
          return({
            label: _.name,
            value: _.id
          })})}

Upvotes: 2

Pulkit Aggarwal
Pulkit Aggarwal

Reputation: 2672

I checked the sandbox code and found multiple issues with your code.

  1. You have to change the newData value with update value otherwise it will old data for render.
  2. You have to compare if (data.id === val.value) instead of if (data.id === val) in handleOnValuesChange function.
  3. You have to return data only in else part.

You can check modified implementation on Sandbox

It will be great if you use the state for newData

Upvotes: 1

TheWuif
TheWuif

Reputation: 1036

you are always using the base newData element. so on each call of handleOnValuesChange you have no value set to disabled.

you need to update the newData or use some other temp variable.

also value is the first parameter for the onChange used by antd select.

let newData = [
  {
    id: 123,
    name: "Vijay",
    disabled: false,
  },
  {
    id: 345,
    name: "Sanket",
    disabled: false,
  },
  {
    id: 546,
    name: "Hitesh",
    disabled: false,
  },
  {
    id: 789,
    name: "Sameer",
    disabled: false,
  },
  {
    id: 421,
    name: "Akshay",
    disabled: false,
  }
];

const handleOnValuesChange = (val) => {
  console.log("VAL", val);
  newData = newData.map((data) => {
    console.log(data, val);
    if (data.id === val) {
      return {
        ...data,
        disabled: true
      };
    }
    return data;
  });
  console.log("NEW DATA", newData);
};

Upvotes: 1

Related Questions