Selecting next list item with down arrow - javascript

Given a list of divs, I need to be able to use the up and down arrow keys to navigate between items in the list, apply an .ag-menu-option-active class to the currently selected item, and on Enter key, trigger a click on the currently selected list item.
I'm currently able to iterate over the list of items, but on down arrow, it only logs out the second item in the list. As stated above, the user should be able to move up and down the list and have the active class applied to the currently selected item. When the user hits the Enter key, the associated list item should be clicked.
let columnMenuItems = document.querySelectorAll('.ag-menu-option');
document.addEventListener('keydown', e => {
if (e.key === 'ArrowDown') {
for (let i = 0; i < columnMenuItems.length; i++) {
if (columnMenuItems[i].classList.contains('ag-menu-option-active') === true) {
console.log("MENU OPTION SELECTED: ", columnMenuItems[i + 1])
columnMenuItems[i].click();
break;
}
}
}
});
JSFiddle link: link

if(columnMenuItems[i+1] !== undefined){
//add class to next
columnMenuItems[i+1].className= "ag-menu-option ag-menu-option-active"
columnMenuItems[i].className= "ag-menu-option"
}
you can write some other logic to add and remove class but this should work for arrow down.

You were missing the +/- when you are calling .click() method;
Also to prevent the undefined error you should add columnMenuItems-1 in first for loop.
Code should look like this -
if (e.key === 'ArrowDown') {
for (let i = 0; i < columnMenuItems.length-1; i++) {
if (columnMenuItems[i].classList.contains('ag-menu-option-active') === true) {
console.log("MENU OPTION SELECTED: ", columnMenuItems[i + 1]);
columnMenuItems[i].classList.remove('ag-menu-option-active');
columnMenuItems[i + 1].click();
columnMenuItems[i+1].classList.add('ag-menu-option-active');
break;
}
}
}
if (e.key === 'ArrowUp') {
for (let i = columnMenuItems.length - 1; i > 0; i--) {
//console.log("MENU OPTIONS: ", columnMenuItems[i]);
if (columnMenuItems[i].classList.contains('ag-menu-option-active') === true) {
columnMenuItems[i].classList.remove('ag-menu-option-active');
//if (e.key === 'Enter') {
columnMenuItems[i - 1].click();
columnMenuItems[i-1].classList.add('ag-menu-option-active');
//}
break;
}
}
}
Test it here (jsfiddle)

Related

Vuejs vuelidate array for object

I have a problem with the Vue vuelidate. Every time the boxes in the picture are pressed, an object is sent to an array. All boxes can be selected.
The condition is that a maximum of 3 boxes must be selected, if more than 3 are selected, I don't want to send the form.
Below is the code that runs when any box is pressed.
valueSelected(value,index) {
// console.log(index)
// console.log(value)
const i = this.mySelectedValue.indexOf(value)
// console.log('const i',i)
if (i === -1) {
this.mySelectedValue.push(value)
} else {
this.mySelectedValue.splice(i, 1)
}
const findIndex = this.user.positions.findIndex(v => {
return v.position === value.position
})
if (findIndex === -1) {
this.user.positions.push(value)
} else {
this.user.positions.splice(findIndex, 1)
}
},
Considering this is the whole function you call. You can just put an if around it so if 3 options are already selected then it will not trigger. I think this is the easy way out.
valueSelected(value,index) {
// console.log(index)
// console.log(value)
const i = this.mySelectedValue.indexOf(value)
// console.log('const i',i)
if (i === -1) {
if(this.mySelectedValue.length < 3){
this.mySelectedValue.push(value)
}
} else {
this.mySelectedValue.splice(i, 1)
}
const findIndex = this.user.positions.findIndex(v => {
return v.position === value.position
})
if (findIndex === -1) {
if(this.user.positions.length < 3){
this.user.positions.push(value)
}
} else {
this.user.positions.splice(findIndex, 1)
}
},

Increment and decrement button with 'keydown' (ArrowUp and Down)

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>

Get and search for the hovered link URL "only"

As the title suggests
「 Get and search for the hovered link URL "only" 」
What corrections would be needed to achieve this?
// Pattern1⃣ Malfunction
// ① Opens all URLs that contain the specified word, regardless of mouse over target.
// ② Opens with or without mouseover.
var ele = document.querySelectorAll(".centerarticle-entry-title a");
var link = ['Loading...', 'Dance Party'];
var L = window.onload = function(load) {
window.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.keyCode === 13) { // CTRL + ENTER
for (let i = 0; i < ele.length; i++) {
for (let j = 0; j < link.length; j++) {
if (!link.onmouseenter) {
e.stopPropagation();
}
if (ele[i].innerHTML.match(link[j])) {
ele[i].innerHTML.match(link[j]).onmouseenter = window.open("https://web.archive.org/web/" + ele[i].href);
L = undefined;
ele[i].onmouseenter = undefined;
ele[i].onmouseenter = null;
}
}
}
} else {
ele[i].onmouseleave = e.preventDefault();
return false;
}
});
};
In the case of Pattern1⃣, this is practical and convenient in another sense, but the function we want to implement this time is different from Pattern1⃣.
The function you want to implement is
「 Get and search for the hovered link URL "only" 」
I am particular about it.
I've created a few other prototypes, but they're even less practical because the version of Pattern 1⃣ is even worse or the search results are empty.
// Pattern2⃣ Malfunction
// ① Opens all URLs that contain the specified word, regardless of mouse over target.
// ② There is a 'case' that opens even if you don't mouse over.
// ③ In some cases, nothing responds in the first place, in which case you need to do a super reload etc. each time.
// ④ The number of times you pressed the ENTER key to the sky may have accumulated. Alternatively, the number of hovering times can be accumulated as it is. That possibility can open duplicate TABs unnecessarily.
var ele = document.querySelectorAll(".centerarticle-entry-title a");
var link = ['Loading...', 'Dance Party'];
document.addEventListener('mouseenter', (m_enter) => {
document.addEventListener('mouseleave', (m_leave) => {
m_enter.preventDefault();
e.preventDefault();
return false;
});
window.addEventListener('keydown', (e) => {
if (!(e.ctrlKey && e.keyCode == 13)) {
m_enter.preventDefault();
return false;
}
if (e.ctrlKey && e.keyCode == 13) {
for (let i = 0; i < ele.length; i++) {
for (let j = 0; j < link.length; j++) {
if (ele.innerHTML.match(link[j])) {
link[j].onmouseover = window.open("https://web.archive.org/web/" + ele[i].href);
location.reload();
break;
}
}
}
} else {
return false;
}
});
});
// Pattern3⃣ Malfunction
// ① Opens only one (probably top) URL that contains the specified word, regardless of whether you hover your mouse over the target.
// ② Opens with or without mouseover.
var ele = document.querySelectorAll(".centerarticle-entry-title a");
var link = ['Loading...', 'Dance Party'];
window.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.keyCode === 13) { // CTRL + ENTER key
for (let i = 0; i < ele.length; i++) {
for (let j = 0; j < link.length; j++) {
if (ele[i].innerHTML.match(link[j])) {
link[j].onmouseover = window.open(("https://web.archive.org/web/" + ele[i].href));
return false;
}
}
}
}
});
// Pattern4⃣ Malfunction
// ① Opens with or without mouseover.
// ② Search results are empty or "undefined"
var ele = document.querySelectorAll(":hover");
var link = ['Loading...', 'Dance Party'];
window.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.keyCode == 13) {
link.onmouseenter =
window.open("https://web.archive.org/web/" + this.href);
return false;
}
});
The actual experiment target pages are as follows.
https://b.hatena.ne.jp/search/tag?q=bookmarklet&page=67
please tell me,
Google
Yahoo
<script>
document.onkeydown = () => {
const link = document.querySelector('a:hover')
if (link) window.open(link.href)
}
</script>

P5.JS Key Pressed Function restricting me

So I'm making a shop kind of place and I'm trying to let the player purchase the first item in the shop's object array by pressing the number 0 but the key pressed isn't letting me access into the if statement. I'm able to tell it is because of the key because when I removed that restriction I was allowed access into the if statement.
else if (inShop === true && key === "1") {
if (player.coins > 50) {
var buying = true
}
for (var i = 0; i < shop.length; i++) {
console.log(shop[i].name, shop[i].price + " press " + i + " to purchase")
}
}
if (buying === true && player.coins > shop[0].price && key=== "0") {
console.log("yo")
player.coins = player.coins - shop[0].price
console.log(player.coins)
sceneNumber = sceneNumber + 1
}
If this is all in the keyPressed block, I think I know what your problem is.
When you press any key, whatever key is pressed is saved as the key variable. Then the computer runs the code that's in the keyPressed block. It does not listen for user input in the middle of that block, but waits until the end. Sort of like this (I might have some details wrong):
run setup block
listen for user input: no input heard
run draw block
listen for user input: no input heard
REPEAT the above 2 things over and over
run draw block
listen for user input: the "1" key was pressed
key = '1'; keyCode = 49;
run keyPressed block
run draw block
etc.
That pretty much means that you can't do multiple layers of input in the keyPressed block. Since buying === true only if key === '1', the statement buying === true && key === "0" is always false.
Often, the keyPressed block will look something like this:
function keyPressed() {
if (key === "1") {
...
} else if (key === "2") {
...
} ...
}
One solution is to turn buying into a global variable:
let buying = false;
function setup() {
...
}
function draw() {
...
}
function keyPressed() {
if (key === "1") {
if (inShop) {
if (player.coins > 50) {
buying = true;
}
for (var i = 0; i < shop.length; i++) {
console.log(shop[i].name, shop[i].price + " press " + i + " to purchase");
}
}
} else if (key === "0") {
if (buying && player.coins > shop[0].price) {
console.log("yo");
player.coins = player.coins - shop[0].price;
console.log(player.coins);
sceneNumber = sceneNumber + 1;
buying = false; //I don't know if you'd want this to happen.
}
}
}

if condition depending on css

I have a problem which has bothered me for a day now and I can't get it right. I have a couple of keydown functions, that changes the background image in certain states, if the class 'active' is not in use.
Like this:
if ($('li').hasClass('active')) {
letterIndex = letterIndex + 1;
$(this).html(letters[letterIndex]);
}
else {
$('.content').css("background-image", "url(img/screen-back.jpg)");
$('li').blur(); // remove focus
}
The thing I want is that when you press up, the background image is updated to a new image (this works) and then with the new background active, I want to be able to press enter to go to a url (this doesn't work).
Example:
case key.enter:
if (letterIndex == 0 && $(this).hasClass('active')) {
$(this).prev().remove();
}
else if ($('.content').css('background-image') === 'url(img/screen-default.jpg)') {
// go to url
}
else {
$(this).closest('li').toggleClass('active');
}
break;
If the default background image is active, the if condition works, but if I change it to another image, nothing happens. Unfortunately I'm unable to add all the images but I've created a fiddle for reference. I would be very thankful to any kind of help in the right direction!
Fiddle
Try:
var letters = [
'<','.',',',';',':',
'a','b','c','d','e','f','g','h','i','j',
'k','l','m','n','o','p','q','r','s','t',
'u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J',
'K','L','M','N','O','P','Q','R','S','T',
'U','V','W','X','Y','Z',
'1','2','3','4','5','6','7','8','9','0'
];
$('li:first').focus().addClass('active');
$('li').on('click', function(e){
$('li').removeClass('active');
$(this).addClass('active');
})
$('li').on('keydown', function(e) {
e.preventDefault();
var keyCode = e.which;
key = {up: 38, down: 40, right: 39, left: 37, enter: 13};
letterIndex = letters.indexOf($(this).text());
switch(e.which) {
case key.up:
if ($('li').hasClass('active')) {
letterIndex = letterIndex + 1;
$(this).html(letters[letterIndex]);
}else {
$('.content').css("background-image", "url(img/screen-back.jpg)");
$('li').blur(); // remove focus
}
break;
case key.down:
if ($('li').hasClass('active')) {
letterIndex = letterIndex - 1;
$(this).html(letters[letterIndex]);
}else {
$('.content').css("background-image", "url(img/screen-check.jpg)");
$('li').blur(); // remove focus
}
break;
case key.right:
// check if li is not active, then move right
if ($('li').hasClass('active')) {
$('li:focus').removeClass('active');
$('li:focus').closest('li').next().focus().addClass('active');
} else if ($('li:last-child').is(':focus')) {
$('.content').css("background-image", "url(img/screen-check.jpg)");
$('li').blur(); // remove focus
}
break;
case key.left:
// check if li is not active, then move left
if ($('li').hasClass('active')) {
$('li:focus').removeClass('active');
$('li:focus').closest('li').prev().focus().addClass('active');
}else {
$('.content').css('background-image', 'url(img/screen-back.jpg)');
$('li').blur(); // remove focus
}
break;
case key.enter:
// check if the first item in array is chosen and active and delete
if (letterIndex == 0 && $(this).hasClass('active')) {
$(this).prev().remove();
}else if ($('.content').css('background-image', 'url(img/screen-default.jpg)')) {
alert('yes');
}else {
$(this).closest('li').toggleClass('active');
}
break;
}
});
http://jsfiddle.net/a91p86wv/7/
Use focus event to check inside up and down key events.
if ($(this).is(':focus')) {
letterIndex = letterIndex + 1;
$(this).html(letters[letterIndex]);
}else {
$('.content').css("background-image", "url(img/screen-back.jpg)");
$('li').blur(); // remove focus
}
Is this what you wanted to do?
http://jsfiddle.net/a91p86wv/5/

Categories

Resources