Search code examples
javascriptjquery

Adding an "onclick" function with setAttribute()


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>

Solution


  • Problem --

    "Why the following is not working? Apparently the function isn't being added!"

    dev_input.setAttribute("onclick","add_device_input(event, this);");
    

    Explanation ---
    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][1]** for the technical reasons and this **[Reddit article][2]** 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

    ###🌟 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][4]**:

    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'-->