JavaScript onclick handlers in quotes giving different behavior? - javascript

I noticed this odd behavior while writing some demonstration code today, and I'm curious what's happening. "Button" does not work although "Button 2" does, even though they're being set in just different ways. I know it has to do with the quoting, but I'm curious why this is happening. Similarly, if I pass in a function to button 3 in quotes vs appending it directly in button 4, button 4 works but button 3 doesn't.
Also, I would think that given that button 2 works, it would do the evaluation of console.log("test") immediately (similar to how it would work without the quotes) but rather it delays until actually clicking on the button. I know this is not the best way to do it but for curiosity sake, I'm curious what's happening exactly here.
document.getElementById("app").innerHTML = `
<h1>Testing Sandbox</h1>
<div>
<button id='hello'>Button</button>
<button id='hello2' onclick='console.log("test")'>Button 2</button>
<button id='hello3' onclick='(e) => console.log("test")'>Button 3</button>
<button id='hello4'>Button 4</button>
</div>
`;
document.getElementById("hello").onclick = 'console.log("test")';
document.getElementById("hello4").onclick = (e) => console.log("test");
<!DOCTYPE html>
<html>
<head>
<title>Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app"></div>
<script src="src/index.js">
</script>
</body>
</html>

When you assign to onclick, you invoke a setter, which does something pretty similar to calling addEventListener with the assigned expression. But both addEventListener and onclick will silently fail if the passed expression is not a function:
document.getElementById("app").innerHTML = `
<h1>Testing Sandbox</h1>
<div>
<button id='hello'>Button</button>
`;
document.getElementById("hello").onclick = 'console.log("test")';
// nearly the same thing as:
document.getElementById("hello").addEventListener('click', 'console.log("test")');
<div id="app"></div>
The string does not get implicitly coerced to a function.
In the third example, the inline handler declares a function, but never executes it:
<button id='hello3' onclick='(e) => console.log("test")'>Button 3</button>
which is like
button.addEventListener('click', function(event) {
(e) => console.log("test")
});
The listener runs, but the listener doesn't contain anything other than an unused function expression, so you don't see anything when you click. This might be clearer if you add a log statement:
<button id='hello3' onclick='console.log("listener running;"); (e) => console.log("test")'>Button 3</button>
In general, you should never use inline handlers; they require global pollution, are hard to manage, have string and HTML escaping issues, and are pretty much universally considered to be bad practice. Instead, use addEventListener, and always pass it functions, not strings, for a listener to be properly added.

Why button two works ?
It is possible to associate an action with a certain number of events
that occur when a user interacts with a user agent. Each of the
"intrinsic events" listed above takes a value that is a script. The
script is executed whenever the event occurs for that element. The
syntax of script data depends on the scripting language. HTML Specs
So onclick = script [CT] will be called whenever user interacts, in this case it is an mouse click event
Why button don't work ?
document.getElementById("hello").onclick expects a function where as you're passing string

Related

The difference between html onclick attribute and react cnClick attribute

Suppose I have an HTML button with onclick attribute and its value is calling a function(say fn).
function fn() {
document.querySelector("#greeting").innerHTML = "Hello folks";
}
<button type="button" onclick="fn()">Try it</button>
<p id="greeting"></p>
Question: What is the type of onclick attribute? I mean does onclick wants the result of the function call? From the above example, it seems that onclick attribute needs the result of the function call.
React example:
const { useState } = React;
function App() {
const [greeting, setGreeting] = useState("");
function fn() {
setGreeting("Hello Folks");
}
return (
<div>
<button type={"button"} onClick={fn}>
Try out
</button>
<p> {greeting} </p>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
In the react example, onClick attributes want a function not the result of the function.
What I have concluded from both the examples is: onclick wants the result of the function and onClick wants a function.
They are different though it does the same work.
From the HTML specification:
Event handler content attributes, when specified, must contain valid JavaScript code which, when parsed, would match the FunctionBody production after automatic semicolon insertion.
From the React documentation:
With JSX you pass a function as the event handler, rather than a string.
They are different though it does the same work.
Yes. HTML and JSX are different languages used to construct a DOM.
React is not using HTML directly, the syntax is similar but it's something else and yes it is HTMLish.
This funny tag syntax is neither a string nor HTML.
says here.
You don't get to write HTML inside javascript, you just utilize HTMLish type of syntax and write in react. And even though you use javascript, the flow of the react is a lot different than that of a normal web HTML/JS application (in terms of writing).

Are inline JavaScript event child tags supported in HTML?

Here we have a div with a onclick handler:
<div id="BorderContainer1282" onclick="alert('hello')">
<input id="Button925" type="button" value="Button">
</div >
When clicked it shows an alert dialog.
Does HTML support inline JavaScript in a child tag of the same name, like so:
<div id="BorderContainer1282">
<onclick>alert('hello');</onclick>
<input id="Button925" type="button" value="Button">
</div >
This question is not best practices. It is specifically about HTML supports setting events in a child tag of an HTML element as shown in the example.
NOTE: I tested the code above in example 2 and it does not work in my tests.
If it does not work, would using the following template be an acceptable alternative:
<div id="BorderContainer1282">
<script type="text/javascript">
document.getElementById('BorderContainer1282').addEventListener("click", function(event) {
(function(event) {
alert('hello');
}).call(document.getElementById("BorderContainer1282"), event);
});
</script>
<input id="Button925" type="button" value="Button">
</div >
Again, I'm not concerned about best practices now, only if this feature is supported.
I found a similar question here that is not a duplicate.
Your second example is not valid HTML; there is no <onclick> tag. The reason you are able to execute JavaScript in the first example is because of Event attributes for certain tags.
These attributes allow you to execute arbitrary JavaScript when a certain event is triggered on the given element, and although you are not concerned with best practices here, you should avoid using them if you want to keep your markup clean and organized.
What you are looking for is the <script> tag in your third example, which does allow for the insertion of JavaScript anywhere in your HTML markup, and is what you should use in this case. You can use this tag and addEventListener to attach an event handler to your div. This is the proper usage of the tag in this scenario:
<div id="BorderContainer1282">
<script type="text/javascript">
document.getElementById("BorderContainer1282").addEventListener("click", function(e) {
alert("Hello!");
});
</script>
<input id="Button925" type="button" value="Button">
</div >
Lastly, <script> tags are typically placed at the end of the <body> to ensure that all elements have been loaded before the script executes. You can also accomplish this by wrapping your JavaScript in a window.addEventListener("load", function(){ ... });.

store the 'this' object in an onclick attribute

What I ultimately want is to retrieve the innerHTML of the example script below (the html is to be put in a database). It must include the onclick events also. However in the generated HTML there is no onclick event available.
<html>
</head>
<script>
function test() {
this.goodbye="goodbye!";
this.elem=document.createElement('div');
this.elem.style.border='1px solid #888888';
this.elem.textContent="hello";
this.elem.style.cursor='pointer';
var that=this;
this.elem.onclick=function(){that.say_goodbye();}
document.getElementsByTagName('body')[0].appendChild(this.elem);
}
test.prototype.say_goodbye=function(blockid) {
this.elem.textContent=this.goodbye;
}
</script>
</head>
<body>
<script>var obj = new test();</script>
get html
</body>
</html>
the line of importance is thus:
this.elem.onclick=function(){that.say_goodbye();}
I tried to add it as attribute like:
this.elem.setAttribute('onclick',that.say_goodbye.bind(that));
But is doesn't work. When I click the link in the given code the browser alerts:
<div> onclick="function(){[native code]}" ..... </div>
In this case the HTML now has an 'onclick' event but contains '[native code]' as action.
Anyone an idea on how to make the code work?
The reason you get this is that attribute value is text always and you are trying to put object into it (functions are objects). This case you should rather use this.elem = that.say_goodbye.bind(that).

Using Classes Instead of IDs in HTML5

In another post, I was advised not to use IDs, intead use classes in HTML forms for buttons.
I'm new to HTML5 and Javascript, so how I use the button class, and assign an event handler to the button?
Possible Solution:
<!DOCTYPE html>
<html>
<head>
<title>HTML Button Tag</title>
</head>
<body>
<form>
<button name="button" value="OK" type="button">Click Me</button>
</form>
</body>
</html>
I would then use document.getElementByName() and assign a button handler, correct?
Seriously, anyone saying that:
ids are considered bad practice for quite some time now in HTML, the preferred method are classes
...are plain wrong! id's and classes have their separate usage areas, which in some cases overlap. For automated testing, and css, ID's are extremely useful. Never be afraid to use them!
As an answer to your question, there are several options. Either find the element in javascript, and assign a button handler, or simply add an onclick-function, and assign it directly in your button tag, like this:
<button ... onclick="functionToBeCalled()">Click Me</button>
then you just define the function you'd like to execute in javaScript.

How to use function declaration with jsfiddle

I have some html/javascript that works in my .cshtml file.
When I try to move it in to jsfiddle to experiment with, it does not work.
Not sure if if it's my lack of javascript experience, jsfiddle experience, probably both....
html:
<div>
<button name="startBtn" id="startBtn" onclick="startTimer">Start</button>
</div>
(I have also tried "startTimer()" for the onclick attribute; same result.)
javascript:
function startTimer() { alert("startTimer"); }
When I click the button, I see this in the Console:
Uncaught ReferenceError: startTimer is not defined
What am I overlooking?
(jsfiddle: http://bit.ly/1buQx9t)
jsFiddle Demo
First you have to set the Framework to No wrap - in <head>, instead of onLoad.
Description
onLoad is the same as window.onload=function(){[YOU ARE TYPING HERE]} in JavaScript or $(function(){[YOU ARE TYPING HERE]}); in jQuery.
No wrap - in <head> is the same as <head><script type="text/javascript">[YOU ARE TYPING HERE]</script</head>
No wrap - in <body> is the same as <body>[HTML CODE HERE]<script type="text/javascript">[YOU ARE TYPING HERE]</script></head>
I hope this clears up the settings in jsFiddle, they can be somewhat confusing.
Second your HTML is slightly wrong:
HTML
<div>
<input type="button' value='"Start" onclick="startTimer()"/>
</div>
Description
onclick="startTimer" was changed to onclick="startTimer()" this will execute the function.
First issue: You have the jsfiddle to set on onload so the function is not in global scope.
Second issue, you are not calling the function. You are missing ()
onclick="startTimer()"
You have some weird quotes going on there (in your fiddle) plus you forgot the () after the name of the function. Use:
<input type="button" value=" Start " onclick="startTimer()" />
jsFiddle example
If you're using pure JavaScript in jsfiddle (ie - no jquery, etc), then change the second dropdown to "No wrap - in <head>"
You had some extra misplaced quotes and were not calling the function. Needed to add the () to call it. Finally you needed to change the "onload" to "no wrap - in "
<div>
<input type="button" value="Start" onclick="startTimer()"/>
</div>
The answers above are all right; I just wanted to clarify what/where to change with this picture to solve the issue:
Here is the jsfiddle demo
<button onclick="doThat()">
Click
</button>
function doThat() {
console.log("click happened");
}

Categories

Resources