简体   繁体   中英

Dynamic onclick function assignment with dynamic parameters in JavaScript?

I have this code:

document.getElementById('img'+i).onclick = function(){popup_show('popup',array_msg[i]+'|||'+date('Y-m-d',strtotime(lec_date))+'-==-'+str_view_forConflict, 'AddEditSchedule;;popup_drag2;;EditSched;;'+String(array_msg_id[3])+';;view', 'popup_drag', 'popup_exit', 'screen-center', 0, 0);};

...but when I click on the image, the data of array_msg[i] is the last data of the loop, meaning the index is the length of the loop. I use IE for this.

Please give me an idea on how to do this. In FF, it works fine because I use setAttribute .

@bobince

document.getElementById('img'+i).onclick= popup_show.bind(window, 'popup',array_msg[i]+'|||'+date('Y-m-d',strtotime(lec_date))+'-==-'+str_view_forConflict,'AddEditSchedule;;popup_drag2;;EditSched;;'+array_msg_id[3]+';;view','popup_drag', 'popup_exit', 'screen-center', 0, 0    ); 
                if (!('bind' in Function.prototype)) {
                    Function.prototype.bind= function(owner) {
                        var that= this;
                        var args= Array.prototype.slice.call(arguments, 1);
                        return function() {
                            return that.apply(owner,
                                args.length===0? arguments : arguments.length===0? args :
                                args.concat(Array.prototype.slice.call(arguments, 0))
                            );
                        };
                    };
                }

You need to use a closure . It would help if you provided the loop code as well as the code that is executed in the loop, but assuming you have a standard for loop iterating through an array, the following code should work:

for (var i = 0, l = array.length; i < l; i++)
{
    (function(i) {
        document.getElementById("img" + i).addEventListener("click", function() {
            popup_show("popup", array_msg[i] + "|||" + date("Y-m-d", strtotime(lec_date)) + "-==-" + str_view_forConflict, "AddEditSchedule;;popup_drag2;;EditSched;;" + String(array_msg_id[3]) + ";;view", "popup_drag", "popup_exit", "screen-center", 0, 0);
        }, false);
    })(i);
}

Also, you shouldn't be using setAttribute in Firefox. Instead, use element.onclick or, preferably, element.addEventListener , which allows you to add multiple functions to be called when an event fires and thus this plays nicely with other code (if two bits of code assign a function to, say, a click event in the form element.onclick = function() { ... , then the second assignment overrides the first—not good). I've used element.addEventListener in my code example above.

You've hit the loop-variable-closure problem. This is a very common gotcha in C-style languages with closures, such as JavaScript and Python. See the accepted answer of this question for a solution involving binding the loop variables in a second closure.

A slightly less nested solution is to use function.bind() :

for (var i= 0; i<something.length; i++) {
    document.getElementById('img'+i).onclick= popup_show.bind(window, 'popup',
        array_msg[i]+'|||'+date('Y-m-d',strtotime(lec_date))+'-==-'+str_view_forConflict,
        'AddEditSchedule;;popup_drag2;;EditSched;;'+array_msg_id[3]+';;view',
        'popup_drag', 'popup_exit', 'screen-center', 0, 0
    );
}

however since this method is an ECMAScript Fifth Edition feature not supported by most browsers yet it needs a little help — see the bottom of this answer for a backwards-compatible implementation.

Treby, this is cleaned up version of your answer. The additional anonymous anonymous function that you added isn't necessary.

for (var i = 0, l = array.length; i < l; i++ ) {
  document.getElementById(i + '05').onclick = (function(tmp) {
    return function() { 
      popup_show(
        "popup", 
        array_msg[tmp] + '|||' + date('Y-m-d', strtotime(lec_date)) + '-==-' + str_view_forConflict, 
        "AddEditSchedule;;popup_drag2;;EditSched;;" + String(array_msg_id[3]) + ";;view", 
        "popup_drag", "popup_exit", "screen-center", 0, 0
      );
    };
  })(i);
}

Edited to fix closure issue

Closures. You need to use JavaScript Closures. See if answers to this question help.

Working Answer:

var closures = [];
for (var i = 0; i < array.length; i++){
  closures[i] = (function(tmp) {
        return function() {
        document.getElementById(tmp + '05').onclick = function(){popup_show("popup", array_msg[tmp]+'|||'+date('Y-m-d',strtotime(lec_date))+'-==-'+str_view_forConflict, "AddEditSchedule;;popup_drag2;;EditSched;;"+ String(array_msg_id[3]) +";;view", "popup_drag", "popup_exit", "screen-center", 0, 0)};
        };
})(i);

  closures[i]();
}

Thanks to Steve Harrison Answer. I got an idea to wrap around it

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