Adding an “onclick” function with setAttribute()

我们两清 提交于 2021-02-08 08:11:32

问题


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 and onclick attribute is one and the same🟊.

  • This behavior is is standard with jQuery methods attr() and prop(). 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:
  1. 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 of set/get/removeAttribute() methods and most likely jQuery method attr() as well (untested and not that curious). See Section: Demo - Source: #btn0

    <button onclick="funcName(event)">Discouraged</button>


  2. 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;


  3. 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>
&lt;button id='btn0' onclick="showHide(event, this)"&gt;On-Event Attribute&lt;/button&gt;
</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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!