0

I am using jqGrid and adding buttons dynamically to the grid. After adding those buttons, in the gridComplete attribute, I call my function:

function(){
   var ids = jQuery("#dataTable").jqGrid('getDataIDs');
   for(var i=0;i < ids.length;i++){
        var cl = ids[i];
        $('.ui-loader.ui-corner-all.ui-body-a.ui-loader-default').remove();
        $('#create_' + cl).on('click', function() {
            var $popUp = $("<div/>").popup({
            dismissible : true,
            theme : "b",
            overlyaTheme : "e",
            transition : "pop"
            }).on("popupafterclose", function() {
            $(this).remove();
            }).css({
                'width' : '100%',
                'height' : '100%',
                'padding' : '5px'
            })
            $("<a>", {
                text : "Edit",
            }).buttonMarkup({
                inline : false,
                mini : true,
            }).on("click", function() {
                $popUp.popup("close");
                $('#dataTable').jqGrid('editGridRow', cl);
            }).appendTo($popUp);

            $("<a>", {
                text : "Delete"
            }).buttonMarkup({
                inline : false,
                mini : true,
            }).on("click", function() {
                $popUp.popup("close");
            }).appendTo($popUp);

            $popUp.popup('open').trigger("create");
            });
}

which works fine except for one problem. It seems that the dynamic buttons all receive the same function (clicking on the button in the first row calls what should have been called for the last row, clicking the second button calls the last row's function, etc...) So it seems that I cannot dynamically assign onclick to a large set of buttons. When I think about it I come to think that it should be possible to assign the click methods for each button this way, but I am not really sure, as I am new to jquery/jqgrid. Is there any way to fix this?

Here is my code to add the buttons:

function displayButton(cellvalue, options, rowObject){var act = "<div id='page_" + options.rowId + "'> <a href='#' data-role='button' id='create_"+ options.rowId +"'>Create a popup</a></div>"
    return act; return act;}

which is called by the model of the jqgrid's row.

formatter: displayButton
Aaron C
  • 3
  • 1
  • I had the same problem because they are all being set with the last method you created right? Try using a recursive function to create the buttons instead of a for loop. – brso05 Oct 15 '14 at 20:53
  • Please don't try to solve this with recursion as suggested by the above comment. You may come up with a way to make that work, but is completely unnecessary for fixing a simple function closure problem. – Krease Oct 15 '14 at 22:25

1 Answers1

0

The problem is that your variable cl, used within the handler functions, is bound to the same variable declared outside the function. As you iterate over your loop, the value of cl changes, but the functions you're adding do not change.

Mistakes with variable closure inside loops is a common Javascript programming problem that you need to watch for anytime you're declaring a function inside a loop. There is no "block scope" in Javascript (like in Java), only "function scope".

Basically, the pattern:

for (var i=0; i<len; i++) {
    foo.on('click', function() {
        console.log(i);
    });
}

will always use the same value for i - the last value in the loop. This is almost always not what the programmer wants, and can be fixed with this modification:

for (var i=0; i<len; i++) {
    foo.on('click', (function(bound_i) { 
        return function() {
            console.log(bound_i);
        };
    })(i));
}

In this case, each iteration of the loop creates a new function with a different value for i, bound to the variable bound_i).

Applying this pattern to your code above where I see this problem:

....
.on("click", function() {
   $popUp.popup("close");
   $('#dataTable').jqGrid('editGridRow', cl);
 })
 ....

becomes

....
.on("click", (function(bound_cl) {
   return function() {
       $popUp.popup("close");
       $('#dataTable').jqGrid('editGridRow', bound_cl);
   };
 })(cl));
 ....

For further reference, see this related question.

Community
  • 1
  • 1
Krease
  • 15,805
  • 8
  • 54
  • 86