skip to Main Content

I am using a document.addEventListener("DOMContentLoaded", function ()
to force the input pattern (first must be a letter, then prevent consecutive spaces, etc.)

Now I want to make a 2nd document.addEventListener("DOMContentLoaded", function () for an email.
(I want to prevent multiple .’s and prevent more than 1 @)

Here is my code for both of the above but it isn’t working, it only capitalizes the email (i kept that option on to see if that part works, which it does but nothing else does work.)

Here is the first part (I also tried something else, removing the first }); at the document.addEventListener("DOMContentLoaded", function () at the start of the 2nd as I heard that should work but that didn’t work either.

document.addEventListener("DOMContentLoaded", function() {
  // Function to handle all keypress events
  function handleKeyPress(event) {
    const input = event.target;
    const char = String.fromCharCode(event.which);

    // Prevent first character from being a space
    if (input.selectionStart === 0 && event.code === "Space") {
      event.preventDefault();
      return;
    }

    // Prevent first character from being a non-letter
    if (input.selectionStart === 0 && !/^[a-zA-Z]$/.test(char)) {
      event.preventDefault();
      return;
    }

    // Prevent consecutive spaces
    const lastChar = input.value.charAt(input.selectionStart - 1);
    if (char === " " && lastChar === " ") {
      event.preventDefault();
      return;
    }
  }

  // Attach event listeners to input fields
  const inputs = document.querySelectorAll("input[name='real_name'], input[name='display_name']");
  inputs.forEach(input => {
    input.addEventListener("keypress", handleKeyPress);

    // Set text-transform to capitalize to force capitalization of each word
    input.style.textTransform = "capitalize";
  });
});
document.addEventListener("DOMContentLoaded", function() {
  // Function to handle all keypress events
  function handleKeyPress2(event) {
    const input = event.target;
    const char = String.fromCharCode(event.which);

    // Prevent first character from being a space
    if (input.selectionStart === 0 && event.code === "Space") {
      event.preventDefault();
      return;
    }

    // Prevent consecutive spaces
    const lastChar = input.value.charAt(input.selectionStart - 1);
    if (char === "@" && lastChar === "@") {
      event.preventDefault();
      return;
    }

    var key = event.keyCode || event.charCode || event.which;
    if (key == 32) {
      return false;
    } else {
      return key;
    }
  }

  // Attach event listeners to input fields
  const inputs = document.querySelectorAll("input[name='email']");
  inputs.forEach(input => {
    input.addEventListener("keydown", handleKeyPress2);

    // Set text-transform to capitalize to force capitalization of each word
    input.style.textTransform = "capitalize";
  });
});

2

Answers


  1. You do not need to attach multiple DOMContentLoaded event handlers. You can bind a single one and put all the event handlers for your HTML elements within that.

    The cause of your issue, however, is because you’re using the keydown event on an input of type="email". This has some inconsistent behaviour with type="text" inputs, as you’ve discovered.

    Given your goal, the simplest approach would be to use the built-in HTML validators as this will ensure all fields are given a value on submission, and also ensure the email field is of the correct format. This has the additional benefit of working whether or not the user has Javascript enabled in their browser.

    Here’s a working example:

    function nameInputRestrictor(event) {
      const input = event.target;
      const char = String.fromCharCode(event.which);
    
      // Prevent first character from being a space
      if (input.selectionStart === 0 && event.code === "Space") {
        event.preventDefault();
        return;
      }
    
      // Prevent first character from being a non-letter
      if (input.selectionStart === 0 && !/^[a-zA-Z]$/.test(char)) {
        event.preventDefault();
        return;
      }
    
      // Prevent consecutive spaces
      const lastChar = input.value.charAt(input.selectionStart - 1);
      if (char === " " && lastChar === " ") {
        event.preventDefault();
        return;
      }
    }
    
    document.addEventListener("DOMContentLoaded", function() {
      document.querySelectorAll("input[name='real_name'], input[name='display_name']").forEach(input => {
        input.addEventListener("keypress", nameInputRestrictor);
      });
    });
    label {
      display: block;
    } 
    <form>
      <label>
        Real name: <input type="text" name="real_name" required />
      </label>
      <label>
        Display name: <input type="text" name="display_name" required />
      </label>
      <label>
        Email: <input type="email" name="email" required />
      </label>
      
      <button type="submit">Submit</button>
    </form>

    Also note that using text-transform on an input element is extremely bad practice. This is because the field will then not exactly match what the user has typed in. For example, they may think that they typed in Foo, but they actually entered foo, and your server-side logic will receive foo when the form is submit, which is not what the user believed they provided to you.

    Login or Signup to reply.
  2. First, one does not even necessarily need a 'DOMContentLoaded' handler for dealing with input-element related 'keypress' events, as long as the element-query for the latter’s registration starts after the targeted element/s have been made accessible within the DOM.

    Second, and regardless of whether one registers the event-handling at 'DOMContentLoaded', one always should make use of event-delegation in order to handle input-element related 'keypress' events.

    One would register the event-listener at the closest available parent of all involved input-elements. The main-handler then just needs to validate and distinguish the relevant input-elements in order to forward the element-type/element-name specific handling to the targeted element’s related, more specialized, handler function.

    body { margin: 0; }
    form { width: 32%; }
    fieldset { margin: 0 0 8px 0; }
    label, label > span { display: block; }
    label > span { margin: 4px 0 2px 0; }
    /*
    input[name="email"],
    input[name="real_name"],
    input[name="display_name"] { text-transform: capitalize; }
    */
    .as-console-wrapper { left: auto!important; width: 66%; min-height: 100%; }
    <form>
      <fieldset>
        <legend>User Data</legend>
      
        <label>
          <span>Real Name</span>
          <input type="text" name="real_name" />
        </label>
      
        <label>
          <span>Display Name</span>
          <input type="text" name="display_name" />
        </label>
    
      </fieldset>
      <fieldset>
      
        <label>
          <span>E-mail Address</span>
          <input type="email" name="email" />
        </label>
    
      </fieldset>
    </form>
    
    <script>
    
    // - one does not even need a 'DOMContentLoaded' event listener
    //   for dealing with input-element related 'keypress' events,
    //   as long as the element-query starts after the targeted
    //   element/s have been made accessible within the DOM.
    
    function handleNameFieldKeypress(target, evt) {
      console.log('handleNameFieldKeypress ... target ...', target);
    
      const char = String.fromCharCode(evt.which);
    
      const { selectionStart } = target;
    
      const isNotValid = (selectionStart === 0 && (
    
        evt.code === 'Space' ||
        !/^[a-zA-Z]$/.test(char)
    
      )) || (
    
        char === ' ' &&
        target.value.charAt(selectionStart - 1) === ' '
      );
      if (isNotValid) {
    
        evt.preventDefault();
      }
    }
    function handleEmailFieldKeypress(target, evt) {
      console.log('handleEmailFieldKeypress ... target ...', target);
    
      const { selectionStart } = target;
    
      const isNotValid =
        (selectionStart === 0 && evt.code === 'Space') || (
    
          String.fromCharCode(evt.which) === '@' &&
          target.value.charAt(selectionStart - 1) === '@'
        );
    
      if (isNotValid) {
        evt.preventDefault();
    
        return;
      }
      const key = evt.keyCode || evt.charCode || evt.which;
    
      return (key !== 32) && key;
    }
    
    function handleInputFieldKeypress(evt) {
      const { target } = evt;
    
      let result;
    
      if (target.matches('input[name="real_name"], input[name="display_name"]')) {
    
        result = handleNameFieldKeypress(target, evt);
    
      } else if (target.matches('input[name="email"]')) {
    
        result = handleEmailFieldKeypress(target, evt);
      }
      return result;
    }
    document
      .querySelector('form')
      .addEventListener('keypress', handleInputFieldKeypress);
    
    </script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search