Search code examples
jqueryreactjsjsx

Changing the CSS class of a specific record field in React


I have a table of text boxes and want a given text box to highlight when I change it. I have the CSS class but am not able to apply it to a specific field. Currently the setChanged() makes the entire table highlighted. I should be able to focus it to a given field given that I have access to the ID and the field name within the event handler righ?

function AppCookie() {

    const [cookies, setCookies] = useState();
    const [changed, setChanged] = useState('');

    const onChangeInput = (e, id) => {
        const { name, value } = e.target
       
        setChanged('highlighted-input')
        const editData = cookies.map((cookie) =>
            cookie.id === id && name ? { ...cookie, [name]: value } : cookie
        )
        editData[id-1].name
        setCookies(editData)
    }

        const handleClick = async (event) => {
       
          ...}

      useEffect(() => {
          populateCookieData();
       }, []);

    const contents = cookies === undefined
        ? <p><em>Loading...</em></p> 
       
        : 
        <table className="table table-striped" aria-labelledby="tabelLabel">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Date</th>
                    <th>Name</th>
                    <th>Desc</th>
                    <th>Price</th>
                </tr>
            </thead>
            <tbody>
                {cookies.map(cookie =>
                    <tr key={cookie.id}>
                        <td>{cookie.id}</td>
                        <td>{cookie.date}</td>
                        <td>
                         <input
                            name="name"
                            value={cookie.name}
                            type="text"
                            onChange={(e) => onChangeInput(e, 
      cookie.id)}
                            placeholder="Type Name"
                            className={changed} />
                        </td>
                       
                        <td><input
                            name="desc"
                            value={cookie.desc}
                            type="text"
                            onChange={(e) => onChangeInput(e, cookie.id)}
                            placeholder="Type Desc"
                        /></td>
                         <td><input
                            name="price"
                            value={cookie.price}
                            type="text"
                            onChange={(e) => onChangeInput(e, cookie.id)}
                            placeholder="Type Price"
                            className={changed}/></td>
                        <td>  <button type="submit" onClick={() => handleClick({cookie})}>Update</button></td>
                        
                    </tr>
                )}
            </tbody>
        </table>;



  
    return (
        <div>
            <h1 id="tabelLabel">Cookies</h1>
            {contents}
        </div>
    );

    async function populateCookieData() {
     ...
    }
}

Solution

  • I do not see all your code, but do you use the useState hook:

    const [changed, setChanged] = useState('');
    

    in the same component where you do cookies.map?

    The state created by useState hook is used for the whole component where you call this hook. You store just "highlighted-input" string there, and the changed variable is visible and is absolutely the same for every cookie in your cookies.map cycle.

    In order to highlight a specific input, you must save which one to highlight. And at the moment of the loop where you display the inputs, check if the current one is highlighted.

    I have prepared a code sample that highlights the last edited input. For this purpose, when changing an input in the onChangeInput handler, I use setState to store the ID of the changed cookie.

    const cookies = [
      { id: "lang", desc: "en" },
      { id: "theme", desc: "dark" },
    ];
    
    const highlighted = "highlighted-input";
    
    function CookiesTable() {
      // create the initial state with empty string
      const [lastChangedId, setLastChangedId] = React.useState("");
    
      const onChangeInput = (e, id) => {
        const { name, value } = e.target;
        // write the id of changed cookie to the lastChangedId state
        setLastChangedId(id);
      };
    
      return (
        <table>
          {cookies.map((cookie) => (
            <tr key={cookie.id}>
              <td>{cookie.id}</td>
              <td>
                <input
                  name="desc"
                  defaultValue={cookie.desc}
                  type="text"
                  onChange={(e) => onChangeInput(e, cookie.id)}
                  placeholder="Type Desc"
                  className={lastChangedId === cookie.id ? highlighted : ""}
                />
              </td>
            </tr>
          ))}
        </table>
      );
    }
    
    const rootElement = document.getElementById("root");
    const root = ReactDOM.createRoot(rootElement);
    
    root.render(<CookiesTable />);
    .highlighted-input {
      background-color: aqua;
    }
    <div id="root"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

    If you want, for example, to highlight not only the last but all changed inputs, it is better to store an object in the state:

    // Create the initial state with empty object
    const [changed, setChanged] = useState({});
    
    const onChangeInput = (e, id) => {
      const { name, value } = e.target;
      // add a new property with current cookie id when input is chagned
      setChanged((allChanged) => ({
        ...allChanged,
        [id]: true,
      }));
    };
    
    // ... all other code ...
    
    // check, if current cookie.id is presented in the "changed" state
    className={changed[cookie.id] ? "highlighted-input" : ""}