问题
Why the following is not working? Apparently the function isn't being added!
function activatetypeinput(event, devtype){
//The function is called but it doesn't set the attribute
var dev_input = document.getElementById("device_input");
dev_input.setAttribute("onclick","add_device_input(event, this);");
}
In my HTML I have something like this (among other things):
<select class="text-input" id="device_input">
<option>--</option>
</select>
回答1:
Problem
"Why the following is not working? Apparently the function isn't being added!" ...
dev_input.setAttribute("onclick","add_device_input(event, this);");
Explination
Although I haven't found a reference to this specific circumstance, I'll point out what I observed:
Look in Devtools F12 and you'll see that the
onclick
attribute is added and the value as well. Although it is there and syntactically correct, it doesn't function. See section Demo - Source:#btn3
If the same attribute and value is added via JavaScript as a property it works, as a property. An attribute will not show up in markup, whilst a property does not. For all intents and purposes, the
onclick
property andonclick
attribute is one and the same🟊.This behavior is is standard with jQuery methods
attr()
andprop()
. As an example I see this frequently:👍
$(":checkbox").prop("checked", true);
👎
$(":checkbox").attr("checked", true);
Event Handling
Events are registered to either an element within the DOM or browser related Non-DOM Object like Window. There are 3 types of event registration:
On-event Attribute: Old as dirt and discouraged and frowned upon by the web developing community in general. This is the type of event handler the OP code was trying to create programmatically with
setAttribute()
method. It appears that an on event is beyond the reach ofset/get/removeAttribute()
methods and most likely jQuery methodattr()
as well (untested and not that curious). See Section: Demo - Source:#btn0
<button onclick="funcName(event)">Discouraged</button>
⭐On-event Property: This is event handling is old and looked down upon as well but because it's limited compared to its predecessor Event Listener. An onclick property and onclick attribute are one and the same as far as DOM elements are concerned. Use this and not
setAttribute()
. See section Demo - Source:#btn1
⭐
document.getElementById('id').onclick = funcName;
Event Listener: This type of event handling employs the methods
add/removeEventListener("event", funcName)
and is the most standard, current, and preferred way. See section Demo - Source:#btn2
document.getElementById('id').addEventListener("event", funcName);
For details why the first 2 types of event handling are reviled, read DOM on-event handlers for the technical reasons and this Reddit article for development and design oriented reasons. I'm personally ambivalent about the subject because on-event handlers aren't deprecated and concepts such as separation of presentation, behavior, structure, semantics, etc. are not as important as they were before.
Solution
Other than using an On-event Property🟊 we can parse a htmlString of the entire element with the onclick
attribute. This can be done using:
innerHTML
overwrites content
OR
- 🌟insertAdjacentHTML() doesn't overwrite content; flexible; fast
🌟 See section: Demo - source: #btn4
🌟
var htmlString = `<button onclick="funcName(event, this)">4</button>`
document.querySelector('${selectorOfTarget}').insertAdjacentHTML("${position}", htmlString);
- "selelectorOfTarget": A CSS string that represents the DOM element we wish to insert an htmlString into or around.
"div"
.......: <div id="ID" class="CLASS"></div>"#ID
".......: <div id="ID" class="CLASS"></div>".CLASS"
....: <div id="ID" class="CLASS"></div>#ID + ul
....: <div id="ID" class="CLASS"></div> <ul></ul>#ID + ul li
.: <div id="ID" class="CLASS"></div> <ul><li></li></ul>
"position": A string that determines where the htmlSting will be inseted in relation to the target element:
<!--"beforebegin"--> <ul> <!--"afterbegin"--> <li>ITEM</li> <li>ITEM</li> <li>ITEM</li> <!--"beforeend"--> </ul> <!--"afterend"-->
htmlString: A String that literally represents HTML. Instead of using String Literals, use Template Literals:
String Literal
'<div id="'+ID+'" class="'+CLASS+'">+CONTENT+</div>'
Template Literal
`<div id="${ID}" class="${CLASS}">${CONTENT}</div>`
🟊(See section: Event Handling - list item: 2. On-event Property and section: Demo - source:
#btn1
.)
Demo
var htmlString = `<button id='btn4' onclick='showHide(event)'>4</button>
<div class='content hide'>
<h4>Dynamically Registered On Event Attribute by Parsing htmlString</h4>
<pre><code>
document.querySelector('#btn3+div+hr').insertAdjacentHTML('afterend', htmlString);
</code></pre>
</div>
<hr>`;
function showHide(event) {
var tgt = event.target;
if (tgt.tagName === "BUTTON") {
var code = tgt.nextElementSibling;
code.classList.toggle('hide');
}
return false;
}
//#btn1
//On-Event Property
document.getElementById('btn1').onclick = showHide;
//#btn2
//EventListener
document.getElementById('btn2').addEventListener('click', showHide);
//#btn3
//Dynamically registered On event Attribute by setAttribute() method.
document.getElementById('btn3').setAttribute('onclick', "showHide(event, this)");
//#btn4
//Dynamically Registered On Event Attribute by Parsing htmlString
document.querySelector('#btn3+div+hr').insertAdjacentHTML('afterend', htmlString);
* {
margin: 0;
padding: 0
}
button {
padding: 2px 5px;
}
button+div {
opacity: 1;
transition: opacity 1s ease;
}
.content {
margin: 0 0 20px 0
}
button+div.hide {
opacity: 0;
transition: 1s ease;
}
code {
background: #000;
color: lime;
}
<!--#btn0-->
<button id='btn0' onclick="showHide(event, this)">0</button>
<div class='content hide'>
<h4>On-Event Attribute</h4>
<pre><code>
<button id='btn0' onclick="showHide(event, this)">On-Event Attribute</button>
</code></pre>
</div>
<hr>
<!--#btn1-->
<button id="btn1">1</button>
<div class='content hide'>
<h4>On-Event Property</h4>
<pre><code>
document.getElementById('btn1').onclick = showHide;
</code></pre>
</div>
<hr>
<!--#btn2-->
<button id='btn2'>2</button>
<div class='content hide'>
<h4>EventListener</h4>
<pre><code>
document.getElementById('btn2').addEventListener('click', showHide);
</code></pre>
</div>
<hr>
<!--#btn3-->
<button id='btn3'><del>3</del></button>
<div class='content'>
<h4>Dynamically Registered On Event Attribute by <code>setAttribute()</code> method <b>FAILED</b></h4>
<pre><code>
<del>document.getElementById('btn3').setAttribute('onclick', 'showHide(event)');</del>
</code></pre>
</div>
<hr>
<!--#btn4 is dynamically created and will be inserted here-->
<!--Selector: '#btn3+div+hr' || Position: 'afterend'-->
回答2:
I don't know how you are trying:
function activatetypeinput(event, devtype){
//The function is called but it doessn't set the attribute
var dev_input = document.getElementById("device_input");
dev_input.setAttribute("onclick","add_device_input(event, this);");
}
function add_device_input(e, t){
console.log(t);
}
activatetypeinput();
<select class="text-input" id="device_input">
<option>--</option>
</select>
来源:https://stackoverflow.com/questions/50321775/adding-an-onclick-function-with-setattribute