Unable to change the values of the mapping data in text field

Viewed 53

I have my data in array format inside the object.

Here is the JSON data:

[
  {
    "id": "1",
    "details": [
      { "id": "12wer1", "name": "ABC", "age": 15 },
      { "id": "78hbg5", "name": "FRE", "age": 21 }
    ]
  },
  {
    "id": "2",
    "details": [
      { "id": "po78u9", "name": "TER", "age": 18 },
      { "id": "dre87u", "name": "YUN", "age": 30 }
    ]
  }
]


I want to change the name and age with respective of the "id". It should not get change for another "id". For Example: if i want to change name = "ABC" then it should not change for the Name="FRE". But couldn't able to do that.

Can anyone help me in writing proper onChange funtion for this and validation for text field?

Here is the sample code:

{this.state.Data.map((i) => (
          <>
            {i.details.map((y) => (
              <Grid container justify="center" spacing={2}>
                <Grid item xs={3}>
                  <TextField label="Name" variant="outlined" value={y.name} />
                </Grid>
                <Grid item xs={3}>
                  <TextField label="Age" variant="outlined" value={y.age} />
                </Grid>
              </Grid>
            ))}{" "}
          </>
        ))}
      </>

Here is the working code

2 Answers

Create an onChange handler that consumes the outer and inner array indices, and onChange event and map the old state to the new state using the map index to match the object you want to update.

handleChange = (dataIndex, detailIndex) => (e) => {
  const { id, value } = e.target;
  this.setState(({ Data }) => ({
    Data: Data.map((dataItem, data_index) =>
      data_index === dataIndex
        ? {
            ...dataItem,
            details: dataItem.details.map((item, index) =>
              index === detailIndex
                ? {
                    ...item,
                    [id]: value
                  }
                : item
            )
          }
        : dataItem
    )
  }));
};

Provide the id attributes for the inputs to pass in the event object.

{this.state.Data.map((i, dataIndex) => ( // <-- data index
  <>
    {i.details.map((y, detailIndex) => ( // <-- detail index
      <Grid container justify="center" spacing={2}>
        <Grid item xs={3}>
          <TextField
            label="Name"
            id="name" // <-- id name attribute
            variant="outlined"
            value={y.name}
            onChange={this.handleChange(dataIndex, detailIndex)} // <-- onChange callback
          />
        </Grid>
        <Grid item xs={3}>
          <TextField
            label="Age"
            id="age" // <-- id age attribute
            variant="outlined"
            value={y.age}
            onChange={this.handleChange(dataIndex, detailIndex)} // <-- onChange callback
          />
        </Grid>
      </Grid>
    ))}{" "}
  </>
))}

Edit unable-to-change-the-values-of-the-mapping-data-in-text-field

you need to create an onChange handler and pass to TextField to proper see your value being updated, otherwise it will remain static. Given each object in array has an id you can use it to filter the target object. Make sure to create copies to avoid mutate state directly:

  onChange = (e, itemId, detailId) => {
    const { name, value } = e.target;
    const Data = [...this.state.Data]; // copy Data into new array
    const itemIndex = Data.findIndex((item) => item.id === itemId);

    if (itemIndex === -1) return; // return if item not found
    const item = { ...Data[itemIndex] }; // copy item object
    const detailsIndex = item.details.findIndex(
      (detail) => detail.id === detailId
    );

    if (detailsIndex === -1) return; // return if detail not found
    item.details[detailsIndex] = {
      ...item.details[detailsIndex],
      [name]: value
    };
    Data[itemIndex] = item; // pass new item
    this.setState({ Data });
  };

At TextField pass name attribute, so you can extract e.target.name above. your TextField becomes:

<Grid item xs={3}>
  <TextField
    label="Name"
    name="name"
    variant="outlined"
    value={y.name}
    onChange={(e) => this.onChange(e, i.id, y.id)}
  />
</Grid>
<Grid item xs={3}>
  <TextField
    label="Age"
    name="age"
    variant="outlined"
    value={y.age}
    onChange={(e) => this.onChange(e, i.id, y.id)}
  />
</Grid>

deep-nested-state-handler

Related