Reputation: 71
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";
});
});
Upvotes: -2
Views: 158
Reputation: 13432
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.
Edit
The above described, and beneath implemented approach (event-delegation) achieves exactly what the OP just recently did ask for in one of the comments ...
"How can I make 2 separate systems? One to watch and modify changes to the names, and another to work separately with the email?" Antarctica-UFO // Commented 1 hour ago
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
.addEventListener('DOMContentLoaded', () => {
document
.querySelector('form')
.addEventListener('keypress', handleInputFieldKeypress);
});
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>
//-->
Upvotes: 1
Reputation: 337691
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.
Upvotes: 0