How can I change background colour of a button on key press? - javascript

I've been working on JavaScript on-screen keyboard kind of thing, just for experimentation. I wanted to see if I could detect which key had been pressed, and make the corresponding on-screen keyboard button change colour, similar to many online touch typing courses have.
I have tried many variations of the onkeydown command, but no luck.
//doesn't seem to do anything.
document.getElementById("a").style.backgroundColor="#004f40";
Button's id is simply it's value eg/ the A key is id="a".
Could anyone give me any ideas on how to do this?

Here is an example that sets the color first in CSS and uses javascript addEventListener to listen for a click event and changes the color of the button when clicked, it also removes the attached event listener.
CSS
#a {
background-color: yellow;
}
HTML
<button id="a">My Button</div>
Javascript
document.getElementById("a").addEventListener("click", function onClick() {
this.removeEventListener("click", onClick);
this.style.backgroundColor = "#004f40";
}, false);
On jsfiddle
This example uses the mouse click event, but you will need to look at key events instead of a mouse one, it could be one of many; e.g. keydown, keypress, or keyup.
Update: Here is one possible solution using key events.
CSS
button {
background-color: yellow;
}
Javascript
var start = 97,
end = 122,
button;
while (start <= end) {
button = document.createElement("button");
button.id = button.textContent = String.fromCharCode(start);
document.body.appendChild(button);
start += 1;
}
document.addEventListener("keypress", function onKeypress(evt) {
var element = document.getElementById(String.fromCharCode(evt.charCode || evt.char));
if (element) {
document.addEventListener("keyup", function onKeyup() {
document.removeEventListener("keyup", onKeyup);
element.style.backgroundColor = "yellow";
}, false);
element.style.backgroundColor = "#004f40";
}
}, false);
On jsfiddle
Note: this example is by no means perfect, it it just an example of how to use events.
Update: here is another example that uses all 3 events to de-bounce the keyboard when multiple keys are pressed and released. (Compare it in use with above.)
CSS
button {
background-color: yellow;
}
button:active {
background-color: #004f40;
}
Javascript
var start = 97,
end = 122,
button;
while (start <= end) {
button = document.createElement("button");
button.id = button.textContent = String.fromCharCode(start);
document.body.appendChild(button);
start += 1;
}
var keydown,
keypress = [];
document.addEventListener("keydown", function onKeydown(e1) {
keydown = e1;
}, false);
document.addEventListener("keypress", function onKeypress(e2) {
var record = {
"char": e2.char || e2.charCode,
"key": keydown.key || keydown.keyCode || keyDown.which,
"shiftKey": keydown.shiftKey,
"metaKey": keydown.metaKey,
"altKey": keydown.altKey,
"ctrlKey": keydown.ctrlKey
},
element = document.getElementById(String.fromCharCode(e2.charCode || e2.char));
if (element) {
element.style.backgroundColor = "#004f40";
keypress.push(record);
}
}, false);
document.addEventListener("keyup", function onKeyup(e3) {
var key = e3.key || e3.keyCode || e3.which;
keypress.forEach(function (record) {
if (record.key === key && record.shiftKey === e3.shiftKey && record.metaKey === e3.metaKey && record.altKey === e3.altKey && record.ctrlKey === e3.ctrlKey) {
document.getElementById(String.fromCharCode(record.char)).style.backgroundColor = "yellow";
}
});
}, false);
On jsfiddle
Note: even this is not perfect as it depends on millisecond timing to match keydown and keypress events.

Or alternatively, you could use jQuery:
$(".keyboardButton").mousedown(function(){
$(this).css("background":"#Color-when-pressed");
}
$(".keyboardButton").mouseup(function(){
$(this).css("background":"#Color-when-released");
}
Of course, replace the colors respectively.
Get jQuery
Or pure CSS:
.keyboardButton:active {
background:#Color-when-pressed;
}
.keyboardButton {
background:#Color-when-released;
}
It might be the best, since you won't have to write code for every single button you have, and you probably already have CSS classes for them.

Related

How to detect click+specific key press in javaScript?

I am new to JavaScript and learning event handlers. How to detect click + specific key pressed concurrently? For example click+D, using pure (vanilla) js.
Edit:
I tried this way but its not detecting the click event when key is pressed.
The console.log("key "+keyPressed) statement is also executed continuously while key is in pressed state.
keyPressed=false;
function keyDown(event) {
var x = event.key;
if (x == "a" || x == "A") {
keyPressed=true;
console.log("key "+keyPressed);
}
}
function keyUp(event){
keyPressed=false;
console.log("key "+keyPressed);
}
function clickHelper(event){
console.log("---");
if(keyPressed){
console.log("*****");
}
}
IIRC you cannot use one event to detect if the mouse is held down AND a button is clicked. However, you can set a property called mouseDown of the document and register an event listener for mouse state.
var mouseDown = 0;
document.body.onmousedown = function () {
++mouseDown;
};
document.body.onmouseup = function () {
--mouseDown;
};
document.body.onkeydown = function (e) {
if (mouseDown && e.key === 'd') {
alert('D was pressed while clicking');
}
};
I used some code from this stackoverflow post for this.

How to make a key fire only once when pressed?

I'm making a simple JavaScript game (Space Invaders style) (Top-down space shooter) and I'm trying to make my character shoot a bullet per each 'space' key press. How can I do that?
I have tried multiple approaches, setting a flag, using onkeypress instead of keydown, Google searches (have also encountered this similar question yet it didn't help: Javascript onkeydown event fire only once?)
Below is an example of one solution I have tried.
document.onkeydown = function(e)
{
if(e.keyCode == 32 && space == false)
{
space = true;
}
}
document.onkeyup = function(e)
{
if(e.keyCode == 32) space = false;
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp)
{ if(space === true)
{
p.shoot();
}
window.requestAnimationFrame(gameLoop);
}
Expected results: Key being fired only once.
Actual results: Key is being fired multiple times.
There's really 3 states to a bullet - and, taking into consideration that in classic Space Invaders the player can only have one bullet in flight at a time, this makes things relatively simple
The bullet can be
NONE - doesn't exist
FIRED - i.e. need to create one
EXISTS - it's in flight
The code to handle it is relatively simple too
var BulletState = {
NONE: 0,
FIRED: 1,
EXISTS: 2
};
var bullet = BulletState.NONE;
document.onkeydown = function(e) {
if (e.keyCode == 32 && bullet === BulletState.NONE) {
bullet = BulletState.FIRED;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (bullet === BulletState.FIRED) {
bullet = BulletState.EXISTS;
p.shoot(); // p.shoot needs to set bullet = BulletState.NONE when the bullet expires
}
window.requestAnimationFrame(gameLoop);
}
document.onkeyup = function(e)
{
// not required at all
}
edit: To fire a bullet every press of spacebar (allowing multiple bullets)
var space = false;
var fireBullet = 0;
document.onkeydown = function(e) {
if (e.keyCode == 32 && !e.repeat && !space) {
fireBullet++;
space = true;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
while (fireBullet) {
p.shoot();
fireBullet--;
}
window.requestAnimationFrame(gameLoop);
}
document.onkeyup = function(e)
{
space = false;
}
I use fireBullet++ and fireBullet-- because I guess it's plausible that someone could press and release and press the spacebar within 16ms (single frame) :p
You could also do
function gameLoop(timeStamp) {
if (fireBullet) {
p.shoot();
fireBullet--;
}
window.requestAnimationFrame(gameLoop);
}
that way you still handle multiple bullets OK, but only fire off one per frame - really depends on how you want to handle someone with a very fast trigger finger :p
As #JaromandaX suggested, space = false; after p.shoot(); will give you the desired result:
Reproducing the issue:
var space = false;
var element = document.querySelector('input');
element.onkeydown = function(e) {
if (!space && e.keyCode == 32) {
space = true;
console.log('event fired');
}
};
element.onkeyup = function(e) {
if (e.keyCode == 32)
space = false;
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (space == true) {
console.log('shoot');
}
window.requestAnimationFrame(gameLoop);
}
<input />
EDIT: Added another isShot variable to keep track of shot fired and space key is down in requestAnimationFrame event:
var space = false;
var element = document.querySelector('input');
var isShot = false;
element.onkeydown = function(e) {
if (!space && e.keyCode == 32) {
space = true;
console.log('event fired');
}
};
element.onkeyup = function(e) {
if (e.keyCode == 32) {
space = isShot = false;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (space && !isShot) {
console.log('shoot');
isShot = true;
}
window.requestAnimationFrame(gameLoop);
}
<input />
Here you have two event, on each key press three are three even that get's fired
1. keydown (when user press the key but not yet release the key)
2. keypress (its fired after the keydown event)
3. keyup (When user release the key)
If you want to fire only once for each keypress
implement on of those if implement all of the three all three methods will fired.
Additionally: for safety you can write e.preventDefault().

How to turn on/off a function on a button click?

I have been working in a mini-game-project (Simons game) that many of you may know. Where the computer plays a random sequence of buttons in which players have to follow to go to the next level in the game e.g: [one click first round, two clicks second round..].
I already did all the button effects as well as make the machine plays buttons randomly in a range of ten rounds. So, what I would like to do is use a button to turn on and off the function that makes the computer clicks By Itself using a button.
I already tried using the jQuery function $(startButton).on('click', clickByItself); alone but it did not worked.
$(document).ready(function() {
//four variables representing its button effects
//button blue effect
var blueButtonEffect = code here;
var greenButtonEffect = code here;
var redButtonEffect = code here;
var yellowButtonEffect = code here;
//to be used on the buttonEffects()/clickByItself()
var arr = [blueButtonEffect, redButtonEffect, greenButtonEffect, yellowButtonEffect];
let enabled = true;
let times = 0;
//makes button effects play itself randomly
function clickByItself() {
let random = Math.floor(Math.random() * arr.length);
$(arr[random]).click();
if (++times < 10) {
setTimeout(function() { clickByItself(times); }, 1000);
}
}
clickByItself();
function turnOnTurnOff() {
if (enabled == true) { //TRYING TO TURN ON/OFF THE FUNCTION ON BUTTON CLICK..
$(startButton).on('click', clickByItself);
}else{
$(startButton).on('click', clickByItself);
}
}
Now, I am trying to use a function turnOnTurnOff() to see whether I could do the effect of turning on and off with the click of a the startButton. Thank you.
You can use .off() method of jQuery to remove an event listener as follows.
I added two divs for better demonstration.
One button binds and unbinds (toggles) the click handler of the second button using jQuery's .on() & .off(). When the click handler is bound to the second button, clicking it will update the div with a number. When the click handler is unbounded from the second button, clicking the second button will do nothing. Two lines of interest in the JavaScript code below are decorated with a comment each. The rest is for demonstration.
window.enabled = false;
window.count = 1;
// Initialize the view (for demo)
$(function() {
$('#switchIndicator').html(`<p>${enabled ? 'Switch is ON' : 'Switch is OFF'}</p>`);
$('#btn').html(enabled ? 'You can click me :-)' : 'You CANNOT click me');
});
// Toggle click functionality using jQuery's .on() & .off() methods
function toggle() {
enabled = !enabled;
if (enabled) {
// Line of interest #1: jQuery .on()
$('#btn').on('click', handleClick);
} else {
// Line of interest #2: jQuery .off()
$('#btn').off('click', handleClick);
}
$('#switchIndicator').html(`<p>${enabled ? 'Switch is ON' : 'Switch is OFF'}</p>`);
$('#btn').html(enabled ? 'You can click me :-)' : 'You cannot click me :-((');
$('#btn').removeClass(enabled ? 'disabled' : 'enabled').addClass(enabled ? 'enabled' : 'disabled');
}
function handleClick() {
$('#counter').append(` ${count++}`);
}
/* CSS */
#btn.enabled {
background-color: greenyellow;
}
#btn.disabled {
background-color: lightgray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="switchIndicator"></div>
<button id="switch" onclick="toggle()">On/OFF Switch</button>
<button id="btn"></button>
<div id="counter"></div>
Give this a try:
function clickByItself() {
if(enabled) {
let random = Math.floor(Math.random() * arr.length);
$(arr[random]).click();
if (++times < 10) {
setTimeout(function() { clickByItself(times); }, 1000);
}
}
}
clickByItself();
function turnOnTurnOff() {
if (enabled) {
enabled = false;
} else {
enabled = true;
clickByItself();
}
}
$(startButton).click(function() {
turnOnTurnOff();
});
You could do it in multiple ways. One is to use setInterval instead of setTimeout and store it inside a variable. When you need to stop it, just call clearInterval.

Javascript to trigger one function only if two events are both true

Say I want to activate myFunction only if the user has pressed the paragraph with a key and clicks on it. In the case below, the function will get triggered if any of the events is true.
<p id="p1" onClick="myFunction()" onKeyDown="myFunction()">
Text awaiting to be colored in red</p>
<script>
function myFunction(){
document.getElementById("p1").style.color = "red";
}
</script>
You need one extra variable isKeyDown, and isKeyDown should be set to true on keydown, and set to false on keyup.
And than in click callback check is isKeyDown true, call myFunction.
An example of how you could do it. This works with Enter and normally clicking it. Really you don't need to make p focus but I thought it was neat, even though you can still handle the key events from the document and since the click only registers on p there's nothing to worry about.
var p = document.getElementById('p1');
p.addEventListener('mousedown', function(e) {
p.clicked = true;
checkEvents(p);
});
p.addEventListener('mouseup', function(e) {
p.clicked = false;
});
p.addEventListener('keydown', function(e) {
if (e.keyCode === 13) {
p.enterDown = true;
}
});
p.addEventListener('keyup', function(e) {
checkEvents(p);
if (e.keyCode === 13) {
p.enterDown = false;
}
});
function checkEvents(el){
if(el.enterDown && el.clicked){
el.style.backgroundColor = 'red';
}
}
p:focus {
outline: none;
}
<p id="p1" tabindex='0'>
Text awaiting to be colored in red</p>
You'll need to breakdown into two methods. First is keystrokes->click and then click->keystrokes. I'm not sure if this is achievable on pure/vanilla javascaript. But on jquery it goes something like:
$('#p1' ).keydown(function() {
if($('#p1').click()) {
document.getElementById("p1").style.color = "red";
}
});
$('#p1')click(function () {
if($('#p1').keydown()) {
document.getElementById("p1").style.color = "red";
}
});

select multiple rows using control and shift key

Demo
<table id="tableStudent" border="1">
<thead>
<tr><th>ID</th><th>Name</th> <th>Class</th></tr>
</thead>
<tbody>
<tr><td>1</td><td>John</td><td>4th</td></tr>
<tr><td>2</td><td>Jack</td><td>5th</td></tr>
<tr><td>3</td><td>Michel</td><td>6th</td></tr>
<tr><td>4</td><td>Mike</td><td>7th</td></tr>
<tr><td>5</td><td>Yke</td><td>8th</td></tr>
<tr><td>6</td><td>4ke</td><td>9th</td></tr>
<tr><td>7</td><td>7ke</td><td>10th</td></tr>
</tbody>
</table>
$('tr').on('click',function(e)
{
var objTR=$(this);
});
I have to select multiple rows using control key.
And then store Student ID in array.
How should i do using jquery Click event.
If you only want the cells to light up when the control key is pressed, this code does the trick:
var studendIds = [];
$(window).on('keydown',(function()
{
var target = $('tr'),
root = $(window),
clickCb = function(e)
{
if (!$(this).hasClass('ui-selected'))
{
$(this).addClass('ui-selected');
//add id to array
studentIds.push(+(this.cells[0].innerHTML))
}
else
{
$(this).removeClass('ui-selected');
for(var i=0;i<studentIds.length;i++)
{
if (studentIds[i] === +(this.cells[0].innerHTML))
{//remove id from array
delete studentIds[i];
break;
}
}
}
},
upCb = function(e)
{
target.off('click',clickCb);
root.on('keydown',downCb);
root.off('keyup',upCb);
},
downCb = function(e)
{
if (e.which === 17 || e.which === 16)
{//17 is ctrl, 16 is shift
root.off('keydown',downCb);
root.on('keyup',upCb);
target.on('click',clickCb);
}
};
return downCb;
}()));
Fiddle demo.
What this code does, essentially, is listen for a keydown event. If that key is the ctrl key (code 17), a click listener is attached, that will set/unset the ui-selected class if a particular row is clicked. The handler also detaches the keydown listener itself and attaches a keyup listener that sets up the event listeners back to their original states once the ctrl key is released.
Meanwhile, another listener is attached, that picks up on the keyup event. If the key (ctrl) is released, the click listener is removed, and the keydown event listener is restored.
As I said in the comments, though the code above does keep track of which ids are selected, I'd personally not do that.
Whenever you need those ids (probably on form submission, or to perform an ajax request), seeing as you have those rows marked usign a class, I'd just do this:
function assumingAjaxFunction()
{
var data = {some: 'boring', stuff: 'you might send', ids: []};
$('.ui-selected > td:first').each(function()
{
data.ids.push($(this).text());
});
console.log(data.ids);//array of ids
}
VanillaJS fiddle with shift-select support
and the code to go with it:
window.addEventListener('load',function load()
{
'use strict';
var tbl = document.getElementById('tableStudent');
window.addEventListener('keydown',(function()
{
var expr = /\bui\-selected\b/i,
key, prev,
clickCb = function(e)
{
e = e || window.event;
var i, target = (function(elem)
{//get the row element, in case user clicked on cell
if (elem.tagName.toLowerCase() === 'th')
{//head shouldn't be clickable
return elem;
}
while(elem !== tbl)
{//if elem is tbl, we can't determine which row was clicked anyway
if (elem.tagName.toLowerCase() === 'tr')
{//row found, break
break;
}
elem = elem.parentNode;//if td clicked, goto parent (ie tr)
}
return elem;
}(e.target || e.srcElement));
if (target.tagName.toLowerCase() !== 'tr')
{//either head, table or something else was clicked
return e;//stop handler
}
if (expr.test(target.className))
{//if row WAS selected, unselect it
target.className = target.className.replace(expr, '');
}
else
{//target was not selected
target.className += ' ui-selected';//set class
}
if (key === 17)
{//ctrl-key was pressed, so end handler here
return e;
}
//key === 16 here, handle shift event
if (prev === undefined)
{//first click, set previous and return
prev = target;
return e;
}
for(i=1;i<tbl.rows.length;i++)
{//start at 1, because head is ignored
if (tbl.rows[i] === target)
{//select from bottom to top
break;
}
if (tbl.rows[i] === prev)
{//top to bottom
prev = target;//prev is bottom row to select
break;
}
}
for(i;i<tbl.rows.length;i++)
{
if (!expr.test(tbl.rows[i].className))
{//if cel is not selected yet, select it
tbl.rows[i].className += 'ui-selected';
}
if (tbl.rows[i] === prev)
{//we've reached the previous cell, we're done
break;
}
}
},
upCb = function(e)
{
prev = undefined;//clear prev reference, if set
window.addEventListener('keydown',downCb,false);//restore keydown listener
tbl.removeEventListener('click',clickCb, false);//remove click
window.removeEventListener('keyup',upCb,false);//and keyup listeners
},
downCb = function(e)
{//this is the actual event handler
e= e || window.event;
key = e.which || e.keyCode;//which key was pressed
if (key === 16 || key === 17)
{//ctrl or shift:
window.removeEventListener('keydown',downCb,false);//ignore other keydown events
tbl.addEventListener('click',clickCb,false);//listen for clicks
window.addEventListener('keyup', upCb, false);//register when key is released
}
};
return downCb;//return handled
}()), false);
window.removeEventListener('load',load,false);
}, false);
This code is close to copy-paste ready, so please, at least give it a chance. Check the fiddle, it works fine for me. It passes JSlint in with fairly strict settings, too (/*jslint browser: true, white: true */), so it's safe to say this code isn't that bad. Yes it may look somewhat complicated. But a quick read-up about how event delegation works will soon turn out that delegating an event is easier than you think
This code also heavily uses closures, a powerful concept which, in essence isn't really that hard to understand either, this linked answer uses images that came from this article: JavaScript closures explained. It's a fairly easy read, but it does a great job. After you've read this, you'll see closures as essential, easy, powerful and undervalued constructs, promise
First of all, define some classes which will indicate that you have selected a table row:
tr.selected, tr.selected td {
background: #ffc; /* light-red variant */
}
Then write this jQuery event handler:
$('table#tableStudent').on('click', 'tr', function() {
if($(this).hasClass('selected')) {
// this accours during the second click - unselecting the row
$(this).removeClass('selected');
} else {
// here you are selecting a row, adding a new class "selected" into <tr> element.
// you can reverse the IF condition to get this one up above, and the unselecting case down.
$(this).addClass('selected');
}
});
In this way you have the expirence that you have selected a row. If you have a column which contains a checkbox, or something similar, you might want to do that logic inside the event listener I provided you above.
This might help DEMO:
function bindMultipleSelect(element){
var self = this;
var isCtrlDown = false;
element.on('click', 'tr', function(){
var tr = $(this);
if(!isCtrlDown)
return;
tr.toggleClass('ui-selected')
})
$(document).on('keydown', function(e){
isCtrlDown = (e.which === 17)
});
$(document).on('keyup', function(e){
isCtrlDown = !(e.which === 17)
});
self.getSelectedRows = function(){
var arr = [];
element.find('.ui-selected').each(function(){
arr.push($(this).find('td').eq(0).text())
})
return arr;
}
return self;
}
window.myElement = bindMultipleSelect($('#tableStudent'))

Categories