Javascript - Dynamically assign onclick event in t

2019-01-07 20:09发布

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!

7条回答
2楼-- · 2019-01-07 20:32

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);
            }
查看更多
趁早两清
3楼-- · 2019-01-07 20:37

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.

查看更多
啃猪蹄的小仙女
4楼-- · 2019-01-07 20:37

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.

查看更多
做自己的国王
5楼-- · 2019-01-07 20:39

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]);
    });
}
查看更多
叛逆
6楼-- · 2019-01-07 20:44

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);
}
查看更多
▲ chillily
7楼-- · 2019-01-07 20:50

You'll have to do something like this:

btnShow.onclick = (function(opt) {
    return function() {
       showParam(opt);
    };
})(arrOptions[i]);
查看更多
登录 后发表回答