My objective is very simple: I would like to intercept right-key and left-key press and, accordingly, execute a particular JavaScript. In particular, I have two img elements in my HTML that are basically a left and a right arrow to change a central picture:
<img id="goleft" onclick="changePic(this)" src="x"/>
<img id="goright" onclick="changePic(this)" src="y" />
The function changePic(this) is hence capturing the caller object (either left or right arrow) and changing the source accordingly. However, for sampling purpose, let's say here that it will just show in an alert the id of the object:
function changePic(obj) {
alert("hello world");
alert(obj.id);
}
Everything works fine until here. On click event, the Javascript is properly called. However, now I'm implementing a system to capture the key-right and key-left and executing the same action. The following function will capture any key-press event:
document.onkeydown = function (evt) {
evt = evt || window.event;
switch (evt.keyCode) {
case 37:
leftArrowPressed();
break;
case 39:
rightArrowPressed();
break;
}
};
...and, clearly, the two functions "leftArrow" and "rightArrow", I thought, could have simply done this:
function leftArrowPressed() {
changePic(document.getElementById("goLeft"));
}
function rightArrowPressed() {
changePic(document.getElementById("goRight"));
}
However, this does not work. The functions leftArrowPressed and rightArrowPressed are properly called (tested with an alert) but the function changePic is called (because I see the alert "hello world" popping-up but it fails on "obj.id" call). So I believe this issue is related to the way I pass the object from the caller to the listener function: could anyone please tell me what I'm doing wrong?
P.s. I'm a newbie of this language, so please don't hesitate to remark me anything that I've thought is unrelevant for answering the question but actually is not.
Ids are case sensitive, your id is goleft but you try to look it up with goLeft.
I am going to suggest a minor change to your code that might make your life easier:
<img id="goleft" onclick="leftArrowPressed()" src="x"/>
<img id="goright" onclick="rightArrowPressed()" src="x"/>
Change your changePic() function to take a string instead of an element and this will make things a little easier on you.
If you want to stick to your current implementation: you use goLeft in the lookup and it should be goleft. Case sensitive!
Related
In javascript we have addEventlister, this listens to an even and calls a function called a listener function. Is an alternate approach possible where we increment the value of a "let variable" without using a function to do this in case of event being triggered?
Instead of this
let clickVar = 0;
x.addEventListener("click", RespondClick);
function RespondClick() {
clickVar++;
}
Sample Alternate implementation
x.addEventListner(click);
if (event == true){ clickVar++; }
======Edit======
Responding to the comment
The more I read this, the more it seems like an XY problem - is there something else you are trying to solve?`
In my view, the second approach is more intuitive. i.e. why create a function unless it's absolutely necessary.
Responding to the comment
There is no logic to how the second approach. The code you write will be executed once. If you want to run code more than once, you have to call a function. In order to run a function when an event happens, you need an event listener.
This simple amendment should take care of the one-time calling problem.
x.addEventListner(click);
if (event == true){ clickVar++; event=false; }
But the point I am trying to make is function could have been avoided, the code could be easy enough to speak, not only write.
Your second sample doesn't work. That simply isn't how event listeners work. You must use a callback function. If you think the first sample is too verbose, you can use an anonymous function:
let clickVar = 0;
x.addEventListener("click", function() {
clickVar++;
});
Or an arrow function in more modern versions of Javascript
x.addEventListener("click", () => {
clickVar++;
});
So I'm working on a game that will accept user input (up down left right arrow keys). To do so, I will add an event listener that will check when the user presses said keys. I have it set up in the following way:
function gameStart(){
//Generates four random numbers on board
for(gameStart_i = 0; gameStart_i < 4; gameStart_i++){
generateNumber();
}
document.getElementById("start_button").innerHTML = "Reset Game";
document.getElementById("start_button").setAttribute('onclick', 'reset()');
document.getElementById("start_button").id = 'reset_button';
var board = document.getElementById("game_background");
console.log("1");
board.addEventListener("keydown", inputListen(), false);
console.log("1.1");
}
function inputListen(e){
console.log("2");
var code = e.keyCode;
switch(code){
case 37:
alert("left");
break;
case 38:
alert("up");
break;
case 39:
alert("right");
break;
case 40:
alert("down");
break;
}
}
This seems in line with how tutorials show it. However, some tutorials change the addEventListener line with something that would look like this:
board.addEventListener("keydown", inputListen, false); //removes the () after the function
However that doesn't seem to work for me when I look into my console.
When I run my code my console gives me the following error:
1
2
Uncaught TypeError: Cannot read property 'keyCode' of undefined
at inputListen (script.js:86)
at gameStart (script.js:16)
at HTMLButtonElement.onclick (2048Game.html:114)
I think it's because I don't pass any parameters to my function, but none of the online tutorials pass paraements in their addEventListener statement.
Thank you,
Alex
The proper way to do this is indeed to remove the () after inputListen.
Using the () immediately calls the function, which then gives you aforementioned Cannot read property 'keycode' of undefined since no input parameters were given.
You should have also received the error in the console between the two console.log lines, which proves the error came from the addEventListener line.
You want to pass the function without calling it using the line you posted:
board.addEventListener("keydown", inputListen, false); //removes the () after the function
Take a look at this JSFiddle:
function gameStart(){
console.log("before");
document.getElementById("game_background").addEventListener("keydown", inputListen, false);
console.log("after");
}
This should print out to the console
before
after
And then nothing else until it detects a keydown.
It also matters what kind of element you bind this to. An element such as <input> will have no trouble here, but normal non-focusable elements will need the tabindex attribute in order to be focused and respond to a keydown:
<div id="game_background" tabindex="-1">
</div>
You'll need to click the element once to focus onto it, then your events should be captured. More info at this answer.
Yes drop the (), you are using the function itself to the event listener, not the result of the function call.
The keydown event is likely not sent to an arbitrary <div> in the page. Add the event listener to the window itself instead, if you don't want the user to manually click to focus on it.
window.addEventListener('keydown', inputListen);
When you are using events in your HTML, and you include a small bit of JavaScript, what is that called? Is it called a "JavaScript attribute function", just a "JavaScript attribute", or what? ex:
<button onClick="location.href='some_place'">click me</button>
When using events, and you use the return keyword, what is that called? Is there some specific piece of terminology that is used to describe this? I am aware of what it does and how it works, I just do not know what to call it. ex:
<button onClick="return someFunction();">click me</button>
Can these two pieces of JavaScript be combined into one in this attribute? I would like to combine my first two examples into one. When the button is clicked, I want to call a JavaScript function. If the function returns "true", I want the location.href to fire. If the function returns "false", I do not want the location.href to fire.
onclick is the event Handler
return is the return statement once the function reaches the return statement it will stop executing
combining the two function may look like this
function someFunction(){
var x = someBool;
if(x){
location.href='some_place'
}else{
return false;
}
}
onclick is a HTML Attribute that binds an event to the element. The value of the attribute is the body of the event handler. You can write anything you want there, but you're limited by the fact that you need to escape quotes " in your code, otherwise the HTML parser will think that you've finished defining the attribute value.
So your code can be:
<button onclick="if(someFunction()) location.href='some_place';"></button>
but, like Sam Creamer pointed out, you don't need a button for it. You can do it with an a href:
if someFunction returns false, the click event will be canceled, and you won't be redirected anywhere.
If you want more code in the attribute, a more practical way is to do this:
onclick="return someOtherFunction()"
, where someOtherFunction contains all your code.
Or like this JS code:
document.getElementById("the_id_of_the_element").onclick=function() {/* your code here */};
, however this might not work on older browsers (other code is necessary):
function bindEvent(element, type, handler) {
if(element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
element.attachEvent('on'+type, handler);
}
}
bindEvent(document.getElementById("the_id_of_the_element"), 'click', function() {/*Your code here*/ });
You can also use jQuery to bind events, which does exactly the same
$("#the_id_of_the_element").on("click", function() {/*your code here*/});
$("#the_id_of_the_element").on("click", function() {/*some other code*/});
//both will execute
Inline JavaScript, bound to an event.
Same, but explicitly returning a value, like any other JavaScript function can. Here it may affect behavior, e.g., stopping normal event processing if the function returns false.
Just write the location value in the function you're calling.
#3 is a little tricky, though, because a function that doesn't explicitly return a value is returning undefined, which, depending on context, may not be a reasonable thing to do. In this case you might want to explicitly return true to keep things clear.
I am taking a web development class. Today the teacher gave us a piece of code that raised some questions that I haven't been able to satisfactorily solve through my own searching. The code in question was essentially this:
<script>
function selectmouse(e){
...
...
}
document.onmousedown = selectmouse;
</script>
My first question, is this a legitimate way of calling functions? Is this something that is done? I am of course familiar with the typical way of calling functions from HTML elements, for example
<body onmousedown="selectmouse(event)">
The code was supposed to be calling the function and passing it the event object for the onmousedown. After playing with the code for a while I found a few unusual things.
First, if I put parenthesis after the function call, like I am used to doing (i.e. selectmouse();), then the function resolved immediately upon loading the page, with a value of 'undefined' for the variable. This makes intuitive sense to me, because I assume the browser is treating it like a variable assignment and therefore calling the function as it parses the code, as it normally would to assign a variable.
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to. It would call the function when the mouse was pressed in any part of the body, and it sent the event object as the variable for the function. But I can't figure out why. I can't find reference to anything similar to it online, and I've never seen anything like it before. Is this a legitimate way to do something like this? Or is this bad code that happens to be working for some reason and would probably cause problems in the future? Why is it working?
document.onmousedown = selectmouse; //note: never do this except in old browsers
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to.
That's not weird. You are passing the reference of the function to the browser, not executing it.
For example, you have this function:
function callback(){
alert("clicked!");
}
document.body.onclick = callback;
You pass the reference to onclick and the browser will know what function to call when the event is triggered. But if you do it like this:
document.body.onclick = callback();
This will be evaluated into:
document.body.onclick = alert("clicked!");
//Note that this is simplified explanation to visualize what is happening.
//The returned value of alert() is not assigned to onclick.
//To be exact the returned value of callback() is the one that is being assigned.
//Similar to:
// ...onclick = (function(){ alert("clicked!"); })();
Then you will see an alert, and the browser will continue executing the rest of the code:
document.body.onclick = undefined;
<body onmousedown="selectmouse(event)"> <!-- Don't do this too -->
The parentheses are necessary because this code is not executed instantly. It is only executed when the event is triggered.
Anyway, you shouldn't attach events both using .onmousedown or onmousdown="...". There is a better way of doing it:
element.addEventListener("mousedown", callback, false);
Reason: If you use the onmousedown property, you can only attach one mousedown event. In most cases you would want to attach more than one.
Also attaching events inline might cause security problems (cross-site scripting), and that is exactly why Google decided to prohibit all developers from using them in developing Chrome apps/extensions.
This is legitimate code and is working as it should.
The way you are comfortable with is just a method we tried while the web was evolving, but at present we should better use the second way you showed, although its changed bit more to make you understand it in a better way using event bindings.
When you do
function selectmouse(e){
...
...
}
javascript will create a variable named selectmouse and save the function in that variable. So selectmouse is a variable of type function with the function body as its value.
document on the other hand can be related to class or specifically an object which is an instance. Each document and each HTML element or DOM node can have in it variables to store the functions to be called on user events like onmousedown.
so when doing
document.onmousedown = selectmouse;
we are inturn saying
when mousedown happens in document, the function named selectmouse
should be called
If you do
document.onmousedown = selectmouse();
it means
run the function selectmouse immediately and get the result, assign
the result to onmousedown event of the DOM Node document.
And if you ask why this is taken apart from the form
<body onmousedown="selectmouse(event)">
To answer in a simple way, HTML is Hyper Text Markup Language, its sole purpose is to represent formatted data, the quick evolution of web inturn made it deranged with behaviours like this and presentation code like inline css. So to make behaviour and presentation out of HTML and thus a better design we do this.
Please take time to take a look at how you can bind a function to an event which is the current tradeoff in doing this same thing.
For a detailed explanation please check the events sectio of ppk blog here
I think that is correct, because the function is being called within the script as if it were an object, to me is not the best way to do it, I would have like this (with jquery):
$(document).mousedown(function (event) {
// here the content of the function
});
<body onmousedown="selectmouse(event)">
In this example the browser evaluates the result of the expression selectmouse(event) and assigns it to the onmousedown property of the body, event is undefined and the selectmouse doesn't return anything so it's result is undefined.
It is equivalent of the following if it was inside a script tag
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse(event);
</script>
<body onmousedown="selectmouse">
When you remove the () you are assigning a function to the onmousedown property. Now the browser fires your callback method whenever the mousedown event is raised and it bubbles up to the body, passing the current event as the parameter you're declaring as "e". If another element also had an onmousedown event handler declared but it cancelled the event ( by calling event.cancelBubble = true ) the body's onmousedown handler will not be invoked.
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse;
</script>
I come again with my inabilities to comprehend javascript.
I have a draggable library and it has a command that is called like so (the _ag is just namespacing stuff):
_ag.drag(event,targetDiv);
// targetDiv can be a string, btw - converted to an element in the function
so I've got code that looks like so (passing some data with a closure - a new trick to me):
header.onmousedown=function(targetDiv){
return function(){
_ag.drag(event,targetDiv)
}
}(aTargetDiv)
works great! just great! in...IE! SF! Chrome! NOT IN FIREFOX!
No, firefox cannot find the event. Now normally this is easy enough with something like this (formed slightly differently - hope it's still valid):
header.onmousedown=function(event){
alert(event.screenX)
}
However if I decide to pass some parameters in, it blows away event, which I guess is some sort of invisible parameter in FF?
//broken thing 1:
header.onmousedown=function(event){
alert(event.screenX) // somethingToPass in covers event in FF
}(somethingToPassIn)
// broken thing 2:
header.onmousedown=function(event){
alert(event.screenX)
}(event,somethingToPassIn) // event is undefined
SO FIREFOX: How do I send you events? Here's hoping this is a very stupid question, and that hoards of SO folks have the answers! Thanks in advance, I'll be right here banging my head against the wall.
Firefox probably doesn't have support for event, but instead passes it into your function when the event fires. So,
header.onmousedown=function(targetDiv){
return function(e){
e = e || event; //This will give support for global event and passing the event into the function
_ag.drag(e, targetDiv);
}
}(aTargetDiv)
You don't need the closure unless the aTargetDiv variable changes sometime later in the code. Instead, you could do:
header.onmousedown=function(e){
e = e || event;
_ag.drag(e, aTargetDiv);
};