skip to Main Content

This question has been asked and answered before; none of the previous answers given here seem to fix my situation. Therefore I need to ask, once again, why isn’t the event prevented correctly?

document.addEventListener("input", event => {
   if(event.data == '#' || event.data == '+' || event.data == '.' || event.data == ';'){
       event.preventDefault();
       alert("Non-allowed character detected: " + event.data);
       return false;
    }
});

I have tried different versions, for example I added the event.stopPropagation() and event.stopImmediatePropagation() but nothing changed. What am I doing wrong and how do I fix it?

It might help to know that I’m simply trying to stop the input of certain characters.

4

Answers


  1. Your code does not prevent input because you are using an "input" event. The event listener "input" is fired after the input occurs, so its default cannot be prevented.

    Instead, use "keydown" which fires before the action, hence the default action can be prevented.

    Here is your updated code:

    document.addEventListener("keydown", event => {
        if (event.key === '#' || event.key === '+' || event.key === '.' || event.key === ';') {
            event.preventDefault();
            alert("Non-allowed character detected: " + event.key);
            return false;
        }
    });
    

    Also, if you want to stop someone from pasting in such characters using the context menu or drag&drop, you can use all these functions together:

    // Existing code for detecting keystrokes
     document.addEventListener("keydown", event => {
         if (event.key === '#' || event.key === '+' || event.key === '.' || event.key === ';') {
             event.preventDefault();
             alert("Non-allowed character detected: " + event.key);
             return false;
         }
     });
    
    // Code to prevent pasting non-allowed characters
    document.addEventListener("paste", event => {
        var clipboardData = event.clipboardData || window.clipboardData || event.originalEvent.clipboardData;
        var pastedData = clipboardData.getData('text');
        if (pastedData.includes('#') || pastedData.includes('+') || pastedData.includes('.') || pastedData.includes(';')) {
            event.preventDefault();
            alert("Non-allowed character detected in your paste: " + pastedData);
            return false;
        }
    });
    
    // Code to prevent drop non-allowed characters
    document.addEventListener("drop", event => {
        var droppedData = event.dataTransfer.getData('text');
        if (droppedData.includes('#') || droppedData.includes('+') || droppedData.includes('.') || droppedData.includes(';')) {
            event.preventDefault();
            alert("Non-allowed character detected in your drop: " + droppedData);
            return false;
        }
    });
    

    Or if you really want to use input, you can, but first the content will be written, then deleted from the input:

    // Listen to input event
    inputField.addEventListener('input', function(event) {
        var value = event.target.value;
        // Check for disallowed characters
        if (value.includes('#') || value.includes('+') || value.includes('.') 
        || value.includes(';')) {
            alert("Non-allowed character detected.");
            // Remove disallowed characters
            event.target.value = value.replace(/[#+.;]/g, '');
        }
    });
    

    All relevant parts of the above code as executable stack snippet …

    // Existing code for detecting keystrokes
    document.addEventListener("keydown", event => {
      if (event.key === '#' || event.key === '+' || event.key === '.' || event.key === ';') {
        event.preventDefault();
    
        alert("Non-allowed character detected: " + event.key);
        return false;
      }
    });
    
    // Code to prevent pasting non-allowed characters
    document.addEventListener("paste", event => {
      var clipboardData = event.clipboardData || window.clipboardData || event.originalEvent.clipboardData;
      var pastedData = clipboardData.getData('text');
    
      if (pastedData.includes('#') || pastedData.includes('+') || pastedData.includes('.') || pastedData.includes(';')) {
        event.preventDefault();
    
        alert("Non-allowed character detected in your paste: " + pastedData);
        return false;
      }
    });
    
    // Code to prevent drop non-allowed characters
    document.addEventListener("drop", event => {
      var droppedData = event.dataTransfer.getData('text');
    
      if (droppedData.includes('#') || droppedData.includes('+') || droppedData.includes('.') || droppedData.includes(';')) {
        event.preventDefault();
    
        alert("Non-allowed character detected in your drop: " + droppedData);
        return false;
      }
    });
    
    // Listen to input event
    document.querySelector('input[type="text"]').addEventListener('input', function(event) {
      var value = event.target.value;
    
      // Check for disallowed characters
      if (value.includes('#') || value.includes('+') || value.includes('.') || value.includes(';')) {
        alert("Non-allowed character detected.");
    
        // Remove disallowed characters
        event.target.value = value.replace(/[#+.;]/g, '');
      }
    });
    form { width: 80%; }
    label > span { display: block; margin: 4px 0 8px 0; }
    input { width: 99%; }
    <form>
      <fieldset>
        <legend>+++ Some ... Text ... To ... Copy ... From +++</legend>
    
        <label>
          <span># more text to copy from; #</span>
          <input
            type="text"
            required
            pattern="[^#+.;]+"
            placeholder="following chars are not allowed ... #+.;"
          />
        </label>
      </fieldset>
    </form>
    Login or Signup to reply.
  2. This isn’t necessarily the answer you are looking for, but you can do the same with the help of RegEx. Use match to find out if the input has the restricted characters and if yes, remove it with help of replace.

    const input = document.getElementById('inp');
    document.addEventListener("input", event => {
        if (event.data?.match(/[+#;.]/g)) {
          console.log(event.data)
          input.value = input.value.replace((event.data).match(/[#+.;]/g), '');
          alert("Non-allowed character detected: " + event.data);
          return false;
      }
    });
    <input id="inp" type='text'>
    Login or Signup to reply.
  3. As Kobra mentioned, you will need to capture the key during the keydown event.

    I modified their response below; particularity decoupling the key check from the event handler.

    const DISALLOWED_KEYS = new Set(['#', '+', '.', ';']);
    
    const disallowedList = document.querySelector('#disallowed');
    
    renderKeys(disallowedList, DISALLOWED_KEYS);
    
    document.addEventListener('keydown', handleKeyDown);
    document.addEventListener('paste', handlePaste);
    document.addEventListener('drop', handleDrop);
    
    function handleKeyDown(event) {
      if (isKey(event.key)) {
        event.preventDefault();
        console.error("Disallowed character detected: " + event.key);
        activateKey(event.key);
        return false;
      }
    }
    
    function handlePaste(event) {
      const clipboardData = getClipboardData(event);
      const pastedData = clipboardData.getData('text');
      if (containsKey(pastedData)) {
        event.preventDefault();
        console.error("Disallowed character detected in paste: " + pastedData);
        return false;
      }
    }
    
    function handleDrop(event) {
      const droppedData = event.dataTransfer.getData('text');
      if (containsKey(droppedData)) {
        event.preventDefault();
        console.error("Disallowed character detected in drop: " + droppedData);
        return false;
      }
    }
    
    function renderKeys(el, keys) {
      for (let key of [...keys].sort()) {
        el.insertAdjacentHTML('beforeend', `
          <li>
            <kbd data-key="${key}">${key}</kbd>
          </li>
        `);
      }
    }
    
    function activateKey(key) {
      const kbd = disallowedList.querySelector(`kbd[data-key="${key}"]`);
      kbd.classList.add('active');
      setTimeout(() => { kbd.classList.remove('active'); }, 100);
    }
    
    const isKey = (s) => DISALLOWED_KEYS.has(event.key);
    const containsKey = (s) => DISALLOWED_KEYS.values().some(k => s.includes(k));
    
    function getClipboardData(event) {
      return event.clipboardData ||
             window.clipboardData || 
             event.originalEvent?.clipboardData;
    }
    .as-console-wrapper {
      max-height: 4rem !important;
    }
    
    ul#disallowed {
      display: flex;
      list-style-type: none;
      margin: 0;
      padding: 0;
      gap: 0.5rem;
    }
    
    ul#disallowed li {
      margin: 0;
      padding: 0;
    }
    
    kbd {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 1rem;
      border: 0.25rem solid grey;
      border-top-width: 0.125rem;
      padding: 0.125rem;
      font-family: monospace;
    }
    
    kbd.active {
      background: darkgrey;
      border-color: yellow;
      border: 0.25rem solid black;
      border-bottom-width: 0.125rem;
    }
    <input type="text" placeholder="Something (except [#+.;])">
    <hr>
    <h2>Disallowed Keys</h2>
    <ul id="disallowed"></ul>
    Login or Signup to reply.
  4. Quoting the OP …

    … why isn’t the event prevented correctly?

    The input already happened, it’s too late to prevent the changes which came along with it.

    It might help to know that I’m simply trying to stop the input of certain characters.

    In order to achieves the OP’s actual goal, a solution which omits such data for any kind of user input, needs to implement an immediate auto correction which also adapts the input element’s caret position according to the user’s most recent input action …

    document
      .querySelector('input[type="text"]')
      .addEventListener('input', ({ currentTarget }) => {
        const { value, selectionEnd } = currentTarget;
    
        // - replace any occurrence of a non allowed character.
        const sanitizedValue = value.replace(/[#+.;]+/g, '');
    
        // - determine whether the current value and its sanitized variant are the same. 
        const deltaLength = value.length - sanitizedValue.length;
    
        // - in case of wrong user input ...
        if (deltaLength != 0) {
    
          // ... provide the sanitized user input ...
          currentTarget.value = sanitizedValue;
          
          // ... and adapt the caret position accordingly in order to
          //     not interfere with the user's experience/expectation.
          const caretPosition =
            Math.max(0, Math.min(sanitizedValue.length, selectionEnd - deltaLength));
    
          currentTarget.selectionStart = currentTarget.selectionEnd = caretPosition;
        }
      });
    form { width: 80%; }
    label > span { display: block; margin: 4px 0 8px 0; }
    input { width: 99%; }
    <form>
      <fieldset>
        <legend>+++ Some ... Text ... To ... Copy ... From +++</legend>
    
        <label>
          <span>### Auto Correction Input Field ###</span>
          <input
            type="text"
            required
            pattern="[^#+.;]+"
            placeholder="following chars are not allowed ... #+.; ... auto correction will take place."
          />
        </label>
      </fieldset>
    </form>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search