So I am trying to building a simple OPT forum which I have build but now I want to add reverse functionality for example when user press backspace input should focus on previous element.
const inputs = document.querySelectorAll('.input input')
inputs.forEach((e, i) => {
e.dataset.index = i;
e.addEventListener("input", () => {
if (e.value.length >= 1) {
if (e.dataset.index >= i && inputs.length - 1 > i) {
e.nextElementSibling.focus();
}
} else {
if (inputs.length - 1 > i || e.dataset.index < inputs.length) {
e.previousElementSibling.focus();
}
}
})
})
You would have to detect the press of the backspace key.
It looks like you want each input to take exactly one character. In that case I would suggest that you keep the current character selected, and to make arrow keys also move the focus.
Don't name the input element e, as e is usually used as name for the event object -- just to avoid confusion for someone reading your code.
Here is one way to do it:
const inputs = [...document.querySelectorAll('.input input')];
inputs.forEach((input, i) => {
const previous = () => inputs[i-1]?.focus?.();
const next = () => inputs[i+1]?.focus?.();
input.addEventListener("input", () => {
if (input.value.length > 1) input.value = input.value[0];
if (input.value.length) next();
});
input.addEventListener("keydown", (e) => {
if (e.key == "ArrowRight") next();
if (e.key == "ArrowLeft") previous();
});
input.addEventListener("keyup", (e) => {
if (e.key == "Backspace") {
previous();
e.preventDefault();
}
});
});
inputs[0].focus();
// Ensure that current input has its content selected
document.addEventListener("selectionchange", () => {
const input = document.activeElement;
if (inputs.includes(input)) input.setSelectionRange(0, 1);
});
.input input { width: 1em }
<div class="input">
<input><input><input><input><input>
</div>
Related
I need some help with a school assignment. I have two buttons, one for increment and one for decrement. I have four functions, where two of them is for clicking and two for pressing arrow keys. Clicking works fine, but to use arrowUp and ArrowDown i need to click and select the button with the mouse once for it to work. Can i add something to my two lower arrow key functions so that i dont need to click them once before i can start using arrow keys?
let element = document.querySelector('#value')
let buttonIncrease = document.querySelector('#increase')
element.textContent = '1'
let buttonDecrease = document.querySelector('#decrease')
buttonDecrease.disabled = true;
//Increment number by 1 on click
buttonIncrease.addEventListener('click', () => {
element.textContent = Number(element.textContent) + 1
if (element.textContent > 1) {
buttonDecrease.disabled = false;
}
})
//Decrement number by 1 on click
buttonDecrease.addEventListener('click', () => {
element.textContent = Number(element.textContent) - 1
if (element.textContent < 2) {
buttonDecrease.disabled = true;
}
})
//Increment number by 1 on keydown
buttonIncrease.addEventListener('keydown', (up) => {
if (up.key === 'ArrowUp' ) {
element.textContent = Number(element.textContent) + 1
}
if (element.textContent > 1) {
buttonDecrease.disabled = false;
}
})
//Decrement number by 1 on keydown
buttonDecrease.addEventListener('keydown', (down) => {
document.getElementById('decrease')
if (down.key === 'ArrowDown') {
element.textContent = Number(element.textContent) - 1
}
if (element.textContent < 2) {
buttonDecrease.disabled = true;
}
})
you dont need to define muse click on increment and decrement buttons
but to use arrowUp and ArrowDown i need to click and select the button
with the mouse once for it to work.
you can detect whene arrowUp and arrowDown clicked by add event lisner directly to keyboard:
addEventListener("keydown", function (e) { // Do something }
To do what you require you can attach the keydown event handler to the window, so that no matter what element in the DOM has focus, so long as the event can bubble to the window element, the value will be changed.
Also note that you can combine the keydown event handlers in to one, and you can also make the code more succinct and DRY by extracting the repeated logic in to functions:
let buttonIncrease = document.querySelector('#increase');
let buttonDecrease = document.querySelector('#decrease');
let element = document.querySelector('#value');
buttonDecrease.disabled = true;
element.textContent = '1';
const setButtonState = () => buttonDecrease.disabled = parseInt(element.textContent, 10) <= 1;
const updateValue = increment => {
value.textContent = Math.max(1, Number(element.textContent) + increment);
setButtonState();
}
buttonIncrease.addEventListener('click', () => updateValue(1))
buttonDecrease.addEventListener('click', () => updateValue(-1))
window.document.addEventListener('keydown', e => {
e.preventDefault();
let value = Number(element.textContent);
let increment = e.key === 'ArrowUp' ? 1 : e.key === 'ArrowDown' ? -1 : 0;
updateValue(increment);
})
#value {
padding: 3px;
}
<button id="decrease">-</button>
<span id="value">1</span>
<button id="increase">+</button>
Im currently trying to make a website where if i press q the p tag will change from "Q" to "A". This currently works with the code below. However the problem is that when pressing q it needs to go back to "A". I've tried making it work with removeEventListeners but it doesn't seem to work.
<script>
document.addEventListener("keypress", event => {
if (event.key == "q") {
document.getElementById("P1").innerText = "Q"
}
});
</script>
Like #diegod suggested in the comments you should check which character is currently shown in the p element and change the innerText accordingly:
const p1 = document.getElementById("P1");
document.addEventListener("keypress", event => {
if (event.key == "q") {
if (p1.innerText == "A") {
p1.innerText = "Q";
} else {
p1.innerText = "A";
}
}
});
Using ternary operator example:
const p1 = document.getElementById("P1");
document.addEventListener("keypress", event => {
if (event.key == "q") {
p1.innerText = p1.innerText == "A" ? "Q" : "A";
}
});
const $ = (prop) => document.querySelector(prop)
const changeToQ = () => {
$('p').innerText = 'Q'
}
const reset = () => {
$('p').innerText = 'A'
}
document.addEventListener('keydown', (e) => {
if (e.key === 'q') changeToQ()
})
document.addEventListener('keyup', (e) => {
if (e.key === 'q') reset()
})
I think this is what are you looking for
have your tried to make else statement
else{ document.getElementById("P1").innerText = "A"}
I'm making a custom dropdown and want to make good keyboard support. How do I get focus on my first LI when the UL visible. Didn't find answer by my self.
I take code from there https://codepen.io/beforesemicolon/pen/abNpjKo
On CodePen focus on first element works. But on my page - no... please, tell me if you know :)
Here is the code:
function DropDown(dropDown) {
const [toggler, menu] = dropDown.children;
const handleClickOut = e => {
if(!dropDown) {
return document.removeEventListener('click', handleClickOut);
}
if(!dropDown.contains(e.target)) {
this.toggle(false);
}
};
const setValue = (item) => {
const val = item.textContent;
toggler.textContent = val;
this.value = val;
this.toggle(false);
dropDown.dispatchEvent(new Event('change'));
toggler.focus();
}
const handleItemKeyDown = (e) => {
e.preventDefault();
if(e.keyCode === 38 && e.target.previousElementSibling) { // up
e.target.setAttribute("aria-selected", "false");
e.target.previousElementSibling.setAttribute("aria-selected", "true");
e.target.previousElementSibling.focus();
} else if(e.keyCode === 40 && e.target.nextElementSibling) { // down
e.target.setAttribute("aria-selected", "false");
e.target.nextElementSibling.setAttribute("aria-selected", "true");
e.target.nextElementSibling.focus();
} else if(e.keyCode === 27) { // escape key
this.toggle(false);
} else if(e.keyCode === 13 || e.keyCode === 32) { // enter or spacebar key
setValue(e.target);
}
}
const handleToggleKeyPress = (e) => {
e.preventDefault();
if(e.keyCode === 27) { // escape key
this.toggle(false);
} else if (e.keyCode === 13 || e.keyCode === 32) { // enter or spacebar key
this.toggle(true);
} else if (e.shiftKey && e.keyCode === 9) { // tab + shift key
this.toggle(false);
document.getElementById("message_email").focus();
} else if (e.keyCode === 9 ) { // tab key
this.toggle(false);
document.getElementById("message_text").focus();
}
}
toggler.addEventListener('keydown', handleToggleKeyPress);
toggler.addEventListener('click', () => this.toggle());
[...menu.children].forEach(item => {
item.addEventListener('keydown', handleItemKeyDown);
item.addEventListener('click', () => setValue(item));
});
this.element = dropDown;
this.value = toggler.textContent;
this.toggle = (expand = null) => {
expand = expand === null ? menu.getAttribute("aria-expanded") !== "true" : expand;
menu.setAttribute("aria-expanded", expand);
if(expand) {
menu.children[0].focus();
toggler.classList.add('active');
menu.children[0].focus();
document.addEventListener('click', handleClickOut);
dropDown.dispatchEvent(new Event('opened'));
//toggler.blur();
} else {
toggler.classList.remove('active');
toggler.focus();
dropDown.dispatchEvent(new Event('closed'));
document.removeEventListener('click', handleClickOut);
}
}
}
const dropDown = new DropDown(document.querySelector('.message__dropdown'));
Heh... problem was in CSS. Property {transition-duration} was written by me for UL (I mean for changing background color, but I didn't choose {transition-property}).
After I remove {transition-duration} focusing is working well. Oh my God... it tooks fore hours
I tried with this code to detect two keyboard arrows being simultaneously pressed:
document.addEventListener('keydown', event => {
if (event.keyCode === 38) {
console.log('up Arrow')
}
if (event.keyCode === 39) {
console.log('right Arrow')
}
})
But it doesn't work, however hard I try to press them at exactly the same time.
How can I cleanly fix this and detect when both keys are down ?
There's only one keyCode per event. You have to track the keys going down, and up:
// if you keep both up and down keys down, you'll get a message
let downKeys = {}; // the set of keys currently down
document.addEventListener('keydown', event => {
downKeys[event.keyCode] = true;
if (downKeys[38] && downKeys[40]) {
console.log("both down!");
}
});
document.addEventListener('keyup', event => {
downKeys[event.keyCode] = false;
});
(you have to go full page to test this snippet)
Here I use 2 flags to check if you are holding the keys.
If both flags are true then it means that you are holding both keys. So, you can perform anything inside the condition.
let holdKeyUp = false;
let holdKeyRight = false;
document.addEventListener('keydown', event => {
if (event.keyCode === 38) {
holdKeyUp = true;
}
if (event.keyCode === 39) {
holdKeyRight = true;
}
if (holdKeyUp && holdKeyRight) {
console.log("Both keys are pressed.");
}
})
document.addEventListener('keyup', event => {
if (event.keyCode === 38) {
holdKeyUp = false;
}
if (event.keyCode === 39) {
holdKeyRight = false;
}
})
I want to enter only 3 words in a textbox. My JavaScript code is below:
jQuery('#Txt_Report').keyup(function (event) {
if (event.which == 32) {
count = jQuery('#Txt_Report').val().split(' ').length;
if (count > 2) {
/////////////
//How can I stop entering text in txt_report anymore?
/////////////
});
}
}
As you see, I want to block user to not to enter more than 3 words. If someone knows how to handle this please help.
You can't preventDefault using keyup. Using keydown or keypress should work. Here is the example:
$('#Txt_Report').keypress(function(e) {
if (e.which == 32) {
var count = this.value.split(' ').length;
if (count > 2) {
e.preventDefault();
}
}
});
Use event.preventDefault(); with keydown (as suggested by the comments)
Demo: http://jsfiddle.net/wTvmz/
jQuery('#Txt_Report').keydown(function (event) {
if (event.which == 32) {
count = jQuery('#Txt_Report').val().split(' ').length;
if (count > 2) {
event.preventDefault();
}
}
});
Set the disabled attribute to disabled.
jQuery('#Txt_Report').keyup(function (event) {
if (event.which == 32) {
count = jQuery('#Txt_Report').val().split(' ').length;
if (count > 2) {
/////////////
//How can I stop entering text in txt_report anymore?
/////////////
jQuery('#Txt_Report').attr('disabled', 'disabled');
});
}
}
Ref: http://www.w3schools.com/tags/att_input_disabled.asp
Why not utilize "keypress" and return false?
http://jsfiddle.net/kW9tF/
$('#txt').keypress(function (event) {
return false;
});
Updated code example: http://jsfiddle.net/kW9tF/1/
$('#txt').keypress(function (event) {
var count = $(this).val().split(' ').length;
if (count > 2) {
return false;
};
});