Treby
Treby

Reputation: 1320

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))
                            );
                        };
                    };
                }

Upvotes: 1

Views: 6209

Answers (5)

Justin Johnson
Justin Johnson

Reputation: 31300

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

Upvotes: 2

Treby
Treby

Reputation: 1320

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

Upvotes: -1

Salman Arshad
Salman Arshad

Reputation: 272106

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

Upvotes: 1

Steve Harrison
Steve Harrison

Reputation: 125510

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.

Upvotes: 2

bobince
bobince

Reputation: 536399

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.

Upvotes: 2

Related Questions