Home > OS >  React: [Label]-[input]-[edit btn]-[save btn-(hidden)]
React: [Label]-[input]-[edit btn]-[save btn-(hidden)]

Time:06-03

As the title states, Ive got a simple crud operation I could use some help with the useEffect/useState hook in how to implement.

form input/userdetails

I've got the input set to disabled by default, displaying the previous value via the placeholder. The state is then updated via a useState/useEffect hooks. Also, the second button (save) is set to hidden by default.

Goal:

  • essentially, just trying to setup an event listener for each edit-input button: hide the edit button, enable the input, unhide the save button.

  • with a separate (2nd) event listener on the save button: to hide the save button, unhide the edit button, return the input to disabled, turn the placeholder to the new value, and submit the value(I've got a good idea of the last part)

JSX:

<label className="col">
  <div className="row">
    <p className="bold nowrap inline-value-title" >Test Name:&nbsp; </p>
    <input 
      id="display-name-change"
      type="text"
      className="form-reset inline-input"
      onChange={(e) => setDisplayName(e.target.value)}
      value={displayName}
      placeholder={user.displayName}
      disabled
    />
    <button type="button" className="inline-button edit-val-btn">
      <FontAwesomeIcon icon={faPenToSquare}  />
    </button>
    <button type="button" className="hidden inline-button save-val-btn">.  
      <FontAwesomeIcon icon={faCircleCheck}  />
    </button>
  </div>
</label>

My Javascript: (as you can probably tell it's still very Vanilla and I think that's the problem)...

const editValueBtns = document.querySelectorAll('.edit-val-btn');
const saveValueBtns = document.querySelectorAll('.save-val-btn');

useEffect(() => {
    editValueBtns.forEach((button) => {
        button.addEventListener('click', (e) => {
            //e.preventDefault()
            //console.log(e)
            button.classList.add('hidden')
            button.nextSibling.classList.remove('hidden')
            // console.log(button.parentElement.children[1])
            button.parentElement.children[1].removeAttr("disabled") ;
        })
    })

    saveValueBtns.forEach((button) => {
        button.addEventListener('click', (e) => {
            //e.preventDefault()
            //console.log(e)
            button.classList.add('hidden')
            button.previousSibling.classList.remove('hidden')
            //console.log(button.parentElement.children[1])
            button.parentElement.children[1].addAttr("disabled") ;
        })
    })
}, []);

CodePudding user response:

I see your vanilla js way, and raise you the react way. In react, you shouldn't have to use document.querySelector, previousSibling, parentElement, classList.add, classList.remove, addAttr or button.addEventListener. See solution in CodeSandbox or below:

App.jsx

import { Row } from "./components/Row";
import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <Row placeholder="input 1" />
      <Row placeholder="input 2" />
      <Row placeholder="input 3" />
    </div>
  );
}

Row.jsx

import { useState } from "react";

export const Row = ({ defaultValue, placeholder }) => {
  const [value, setValue] = useState(defaultValue);
  const [disabled, setDisabled] = useState(true);

  const handleEditClick = () => {
    setDisabled(false);
  };

  const handleSaveClick = () => {
    setDisabled(true);
    // save logic goes here
  };

  return (
    <label className="col">
      <div className="row">
        <p className="bold nowrap inline-value-title">Test Name:</p>
        <input
          type="text"
          className="form-reset inline-input"
          onChange={(e) => {
            setValue(e.target.value);
          }}
          value={value}
          placeholder={placeholder}
          disabled={disabled}
        />
        {disabled && (
          <button
            type="button"
            onClick={handleEditClick}
            className="inline-button edit-val-btn"
          >
            edit
          </button>
        )}
        {!disabled && (
          <button
            type="button"
            onClick={handleSaveClick}
            className="hidden inline-button save-val-btn"
          >
            save
          </button>
        )}
      </div>
    </label>
  );
};

CodePudding user response:

small tweaks.. it appears that logging the console kept it from doing what it did. also removed the e from the parenthesis after each 'click'. the addAttr and removeAttr also were replaced... the rest of the functionality can be placed in either of the listeners..

EDIT: added a 2nd input and it appears to only work in the 1st input.... ...yes I'm talking to myself.

EDIT 2: It worked fine until the page refreshed... removed the dependency array for it to work every time. I feel like i still need a cleanup function, but I can't just place the event listeners into a function can i? Really, if you're reading this i would love some more experienced input... :)

useEffect(() => {
    editValueBtns.forEach((button) => {
        button.addEventListener('click', () => {
            button.classList.add('hidden')
            button.nextSibling.classList.remove('hidden')
            button.parentElement.children[1].disabled = false ;
        })
    })

    saveValueBtns.forEach((button) => {
        button.addEventListener('click', () => {
            button.classList.add('hidden')
            button.previousSibling.classList.remove('hidden')
            button.parentElement.children[1].disabled = true ;
        })
    })
});
  • Related