0

I'm implementing a search input field, which will trigger searching as the user types, and if the user pastes some text, the app needs to do some extra work after searching.

I'm using React

code demo: https://codesandbox.io/s/blazing-platform-wz7ibo?file=/src/App.js

function App() {
  const [isPaste, setIsPaste] = useState(false);
  const [searchText, setSearchText] = useState('');

  useEffect(() => {
    callSearchApi(searchText).then(() => {
      if (isPaste) {
        doSomeExtraWork();
      }
    });
  }, [searchText, isPaste]);

  return (
    <div>
      <input
        value={searchText}
        onChange={(e) => {
          setIsPaste(false);
          setSearchText(e.target.value);
        }}
        onPaste={(e) => {
          e.preventDefault();
          setIsPaste(true);
          const pasteText = (e.clipboardData || window.clipboardData)
            .getData('text')
            .trim();
          setSearchText(pasteText);
          // document.execCommand('insertText', false, pasteText); // this will trigger a `change` event
        }}
      />
    </div>
  );
}

this implementation seems fine, but because I prevent the default event in the paste handler, the undo (Ctrl+Z) no longer works after pasting,

but if I add document.execCommand at the end of the paste handler, it does bring the undo feature back, but I can no longer tell if the text is changed by paste...

=== update Jun 08 2023 ==== https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

In particular, the Clipboard API doesn't replace the insertText command, which you can use to programmatically replace text at the cursor while preserving the undo buffer (edit history) in plain textarea and input elements.

Littlee
  • 3,791
  • 6
  • 29
  • 61

1 Answers1

2

You can check the value of e.nativeEvent.inputType property. See the complete list of the available input types

import React from "react";
export default function App() {
  const [state, setState] = React.useState("");
  const onChange = (e) => {
    console.log(e);
    if (e.nativeEvent.inputType === "insertFromPaste") {
      console.log("user copy and paste the text");
    } else if (e.nativeEvent.inputType === "insertText") {
      console.log("user types the text");
    }
    setState(e.target.value);
  };
  return <input type="text" value={state} onChange={onChange} />;
}

codesandbox

Lin Du
  • 88,126
  • 95
  • 281
  • 483
  • hi, Lin Du, my situation is more complex, if I manipulate the value from input, the ctrl+z doesn't work also, please see the AppInput3 in https://codesandbox.io/s/sharp-tristan-gent26?file=/src/Input3.js – Littlee Jun 08 '23 at 03:58
  • @Littlee The undo will not work if you change the input value programmatically. see https://stackoverflow.com/questions/16195644/in-chrome-undo-does-not-work-properly-for-input-element-after-contents-changed-p and https://stackoverflow.com/questions/46203724/programmatic-value-change-on-input-field-is-ignored-by-ctrl-z-and-cant-be-undo – Lin Du Jun 08 '23 at 04:43