简体   繁体   中英

Javascript - Dynamically assign onclick event in the loop

I have very simple html page with js code:

<html>
    <head>
        <title></title>
    </head>
    <body>

        <div id="divButtons">

        </div>

        <script type="text/javascript">
            var arrOptions = new Array();

            for (var i = 0; i < 10; i++) {
                arrOptions[i] = "option" + i;
            }

            for (var i = 0; i < arrOptions.length; i++) {
                var btnShow = document.createElement("input");
                btnShow.setAttribute("type", "button");
                btnShow.value = "Show Me Option";
                var optionPar = arrOptions[i];
                btnShow.onclick = function() {
                    showParam(optionPar);
                }

                document.getElementById('divButtons').appendChild(btnShow);
            }

            function showParam(value) {
                alert(value);
            }        
        </script>
    </body>
</html>

That page binds 10 buttons, but when you click on any button it always shows alert "option9". How is it possible assign onclick event to show correspondent option??

Thanks!

You'll have to do something like this:

btnShow.onclick = (function(opt) {
    return function() {
       showParam(opt);
    };
})(arrOptions[i]);

Consider the fact that when the onclick() function is executed, all it has is:

showParam(optionPar);

, verbatim. The optionPar will be resolve at the time the click event is executed, and at this point it most likely be the latest value you assigned to it. You should generally avoid passing variables in such a way.

The problem you are trying to solve is best solved by re-writing the piece such as:

            btnShow.value = "Show Me Option";
            var optionPar = arrOptions[i];
            btnShow.optionPar = optionPar;
            btnShow.onclick = function(e) {
                // if I'm not mistaking on how to reference the source of the event.
                // and if it would work in all the browsers. But that's the idea.
                showParam(e.source.optionPar);
            }

I attach an event handler:

        window.onload = function() {
            var folderElement;
            tagFolders = document.getElementById("folders");
            for (i = 0; i < folders.length; i++) {
                folderElement = folderButtons[i];
                folderElement = document.createElement("button");
                folderElement.setAttribute("id", folders[i]);
                folderElement.setAttribute("type", "button");
                folderElement.innerHTML = folders[i];
                if (typeof window.addEventListener !== "undefined") {
                    folderElement.addEventListener("click", getFolderElement, false);
                } else {
                    folderElement.attachEvent("onclick", getFolderElement);
                }
                tagFolders.appendChild(folderElement);
            }

which can retrieve anything from the element that triggered the event:

// This function is the event handler for the folder buttons.
function getFolderElement(event) {
    var eventElement = event.currentTarget;
    updateFolderContent(eventElement.id);
}

in which case you have to embed the option inside the element / tag. In my case I use the id.

For jquery, check out the adding event data section from the API :

...
for (var i = 0; i < arrOptions.length; i++) {

    $('<input id="btn" type="button" value="Show Me Option"><input>').appendTo("#divButtons")

    $('#btn').bind("click", {
        iCount: i},
    function(event) {
        showParam(arrOptions[iCount]);
    });
}

The accepted answer seems to work, but seems to be confusing and a somewhat cumbersome way to do it. A better way perhaps might be to use the data attribute for the element you're looking to assign the event listener for. It's simple, easy to understand, and way less code. Here's an example:

btnShow.data = arrOptions[i];

btnShow.onclick = function() {
  showParam(this.data);
}

The accepted answer is correct but I feel that no real explanation was done.

Let me try to explain, the issue here is classical missing closure.

The variable 'i' is getting increased by 1 per loop iteration, and the on-click event actually is not being executed , whether only applied to the a element, it getting summarize up to the length of arrOptions which is 10.

So, the loop continues up until 'i' is 10, Then, whenever the on-click event is being triggered, it takes the value of i which is 10.

now, for the solution, in the solution we are using a closure, so that when we apply the value of 'i' to the on-click event of the a element, it actually gets the exact value of i at in time.

The inner function of the onclick event create a closure where it references the parameter (arrOptions[i]), meaning what the actual i variable is at the right time.

The function eventually closes with that value safely, and can then return its corresponding value when the on-click event is being executed.

You pass just the reference of the variable to the function, not it's value. So every time the loop is iterated, it assigns a reference to your anonymous function and all of them point to the same value in memory. But since you use the same variable name in the loop, you overwrite the value of the variable. You can concatenate the variable to a string to preserve it's value. For example like that:

btnShow.onclick = new Function("", "showParam(" + arrOptions[i] + ");");

The first parameter is the name of the function but afaik it is optional (it can be left blank or omitted at all).

  pp();

  function pp()
  {

    for(j=0;j<=11;j++)
    {

      if(j%4==0)
      {
        html+= "<br>";
      }
      html += "<span class='remote' onclick='setLift(this)' >"+ j+"</span>";
    }
    document.getElementById('el').innerHTML = html;
  }

  function setLift(x)
  {
    alert(x.innerHTML);
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM