skip to Main Content

I have an h1 element in my React app that I plan to use with a contentEditable attribute to allow users to edit it directly. The problem is within the useFormValues hook that I use to manage all my other inputs, we are unable to access the e.target.name or e.target.value properties the way we are with a standard input. [Note: Please don’t comment just to recommend I stick with a standard input, I’ve already weighed the pros and cons].

When I log the following console.log(Object.entries(e.target)); I get this array:
Array

The second of these items contains my object along with its properties, but I’m wondering why this doesn’t come directly from e.target. It feels incorrect and risky to access e.target.name with e.target[1][1].name.

Relevant code below, starting with the h1 here:

        <RecipeName
            data-test="recipePage-name"
            length={recipe.recipe.name.length}
            contentEditable={editable}
            onInput={handleChange}
            name="name"
            value={values.name || recipe.recipe.name}
            suppressContentEditableWarning={true}
          >
            {recipe.recipe.name}
          </RecipeName>

And the hook:

const handleChange = e => {
    e.persist();
    let tmp = { ...values };
    let value;
    switch (e.target.type) {
      case 'number':
        value = parseInt(e.target.value);
        break;
      case 'file':
        value = e.target.files[0];
        break;
      case 'contenteditable':
        value = e.target.innerHTML;
        break;
      default:
        value = e.target.value;
    }
    dot.str(e.target.name, value, tmp);
    setValues(tmp);
  };

2

Answers


  1. From the docs, Event: type property:

    The type read-only property of the Event interface returns a string containing the event’s type. It is set when the event is constructed and is the name commonly used to refer to the specific event, such as click, load, or error.

    So, in your case, the event listener is added to onInput meaning the type of the event is input not contenteditable. You just need to change the contenteditable case to input, then it should work.

    Login or Signup to reply.
  2. Let’s go with basic JavaScript and demonstrate some issues with the type, value etc. I made lots of comments in the code using console.log() to show what is what.

    I will leave the reactjs conversion exercise to the OP here.

    function handleChange(event) {
      console.log('we are here');
      // not a function:
      //event.persist();
      //let tmp = { ...values };
      let value;
    
      console.log("Target:", event.target); // the h1 element
      console.log("Target:name", event.target.name); // undefined
      console.log("What:", event.type); // "input"
      console.log("CTarg:", event.currentTarget); // same as target but might not be for delegated events or elements wrapped
      console.log("New:", event.data); //last character entered for an h1
      console.log("ETarget type:", event.target.type); // undefined
      console.log("Target tag:", event.target.tagName.toLowerCase()); //h1
      console.log("Targ cont:", event.currentTarget.textContent); // what it is
      console.log("Targ html:", event.currentTarget.innerHTML); // if <p> entered returns &lt;p&gt;
      console.log("Targ value:", event.target.value); //undefined for h1
      // so you see the target.type is not valid for h1
      // switch (event.target.type) {
      switch (event.currentTarget.tagName.toLowerCase()) {
        case 'number':
          value = parseInt(event.target.value);
          break;
        case 'file':
          value = event.target.files[0];
          break;
          //  case 'contenteditable':
        case 'h1':
          value = event.currentTarget.textContent;
          // value = event.target.innerHTML; // see security warning: https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
          // https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations
          break;
        default:
          value = event.target.value;
      }
      //  dot.str(event.target.name, value, tmp);
      //  setValues(tmp);
    }
    
    let hedit = document.querySelector('h1.findme');
    hedit.addEventListener('input', handleChange);
    document.querySelector('input[type="text"].enterme')
      .addEventListener('input', handleChange);
    .findme {
      caret-color: red;
    }
    <h1 class="findme" contenteditable="true">Howdy</h1>
    <input class="enterme" type="text" value="my default" />
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search