Home > Software engineering >  Update the key value pair in array of object and find if the value is duplicate
Update the key value pair in array of object and find if the value is duplicate

Time:07-29

Requirement - There will be two input fields in one row, one being name and second is number. In the second row, again two fields will be there with one being name and second is number. Now, the name field is readOnly and the second field number can be edited by user.

First time, the state which is in [{}] format would be empty. Now, when the user enters the number in the first row input, the state should get updated as [{ name: 'user1', number: 123}]. When the user enters value in row 2, the state should get updated as [{ name: 'user1', number: 123}, { name: 'user2', number: 456}]. If the user enters the value in row number 1 again, the existing object value should updated then adding a new one.

For example, if the user1's number gets updated to 789, the state value now should be [{ name: 'user1', number: 789 }, { name: 'user2', number: 456}].

Once this is achieved, if the numbers are duplicate, I should store and error in another state and with state, I can show on UI that the numbers are duplicate and need to have a unique number.

 import { useState } from 'react';

const Test = () => {
  const [data, setData] = useState([{}]);
  const [error, setError] = useState(null);

  const handleChange = (number, name) => {
    //set data in the state 
    

    //validation
    //if the values for number are duplicate for both field
    //return an error for which input name the value is duplicate
  }

  return (
    <div>
      <input name='user1' value='user1' readOnly={true} />
      <input name='number1' onChange={(e) => handleChange(e.target.value, 'user1')} />
      <hr />
      <input name='user2' value='user2' readOnly={true} />
      <input name='number2' onChange={(e) => handleChange(e.target.value, 'user2')} />

    </div>
  )
}


CodePudding user response:

Your handleChange function would look like this. Please not that I changed your initial data state to [] since a new user would simply be inserted instead of updating {}. I also prefer an empty state over null.

First we check whether the name already exists in data array. If not, we append it using curr callback. If it exists and we only want to update the specific object, we can make use of map function.

By validating before updating the new user we can easily get the user that already has the value with find and set his name inside error state. Plus you can still decide if you want to update the data state if it has duplicate numbers by putting the // update value of exisiting user block inside of an else.

  const [data, setData] = useState([]);
  const [error, setError] = useState();

  const handleChange = (number, name) => {
    const idx = data.findIndex((item) => item.name === name);
    if (idx === -1) {
      // new user insert
      setData((curr) => [...curr, { name: name, number: number }]);
    } else {
      // validation
      const duplicateUser = data.find((item) => item.number === number);
      if (duplicateUser) {
        setError(duplicateUser.name);
        console.log(`${duplicateUser.name} and ${name} have duplicate number`);
      }

      // update value of exisiting user
      setData((curr) =>
        curr.map((item) => {
          return item.name === name ? { name: name, number: number } : item;
        })
      );
    }
  };

CodePudding user response:

Look out code

import React, { useState } from "react";

export const Test = () => {
  const [data, setData] = useState([]);
  const [error, setError] = useState("");

  const handleChange = (number, name) => {
    setError("");
    let isDuplicate = false;
    if (!data.length) {
      setData([{ name, number }]);
    } else if (data.length == 2) {
      const newData = data.map((val) => {
        if (val.name === name) {
          return { name, number };
        } else {
          isDuplicate = val.number === number;
        }
        return val;
      });
      setData(newData);
    } else {
      const existingData = data.find((val) => val.name === name);
      if (existingData) {
        setData([{ name, number }]);
      } else {
        let [user] = data;
        if (user.number === number) {
          isDuplicate = true;
        }
        setData((oldState) => {
          return [...oldState, { name, number }];
        });
      }
    }
    if (isDuplicate) {
      setError("Number is duplicate! Each field should have uniq number.");
    }
  };

  return (
    <div>
      <div className="error">{error}</div>
      <input name="user1" value="user1" readOnly={true} />
      <input
        name="number1"
        onChange={(e) => handleChange(e.target.value, "user1")}
      />
      <hr />
      <input name="user2" value="user2" readOnly={true} />
      <input
        name="number2"
        onChange={(e) => handleChange(e.target.value, "user2")}
      />
    </div>
  );
};

I hope this will help you. Happy coding...

CodePudding user response:

You have set handleChange event on onChange event so it will call when user enter the single input and check with existing value.

suggestion:- if you want to check whole value which is user enter and compare with the existing value so please use button and click event so it will check when user click after enter the whole value

Hope this will help you. !

import { useState } from "react";

const Test = () => {
  const [data, setData] = useState([]);
  const [error, setError] = useState(null);

  const handleChange = (number, name) => {
    const exists = data.find((e) => e.name === name);
    if (!exists) {
      setData([...data, { name, number }]);
    } else {
      if (exists.number === number) {
        setError("Number already exists");        
      } else {
        if (number) {
          const index = data.findIndex((e) => e.name === name);
          data[index].number = number;
          setData([...data]);
        }
      }
    }

  };
  console.log(data, error);


  return (
    <div>
      <input name="user1" value="user1" readOnly={true} />
      <input
        name="number1"
        onChange={(e) => handleChange(e.target.value, "user1")}
      />
      <hr />
      <input name="user2" value="user2" readOnly={true} />
      <input
        name="number2"
        onChange={(e) => handleChange(e.target.value, "user2")}
      />
    </div>
  );
};

CodePudding user response:

This might work for you [Updated]

export const Test = () => {
  const [data, setData] = useState([]);
  const [error, setError] = useState(null);

  const handleChange = (number, name) => {

    setData((prev) => {
      const newState = [...prev];
      const index = prev.findIndex((entry) => entry.name === name);

      if (index < 0) {
        return [
          ...prev,
          {
            name,
            number
          }
        ];
      } else {
        const dupEntry = prev.find(
          (entry) => entry.name !== name && entry.number === number
        );

        if (dupEntry) setError(new Error(`${dupEntry.name} already has that value`));
        else newState[index].number = number;
      }

      return newState;
    });

    //validation
    //if the values for number are duplicate for both field
    //return an error for which input name the value is duplicate
   
  };

  return (
    <div>
      <input name="user1" value="user1" readOnly={true} />
      <input
        name="number1"
        onChange={(e) => handleChange(e.target.value, "user1")}
      />
      <hr />
      <input name="user2" value="user2" readOnly={true} />
      <input
        name="number2"
        onChange={(e) => handleChange(e.target.value, "user2")}
      />
    </div>
  );
};
  • Related