Search code examples
javascriptextjs4renderer

ExtJS column renderer


My Problem is the renderer function of a column in a GridPanel in ExtJS 4. The record of the renderer should load an element of my list from my store, and it does; but it always loads the same element of the list.

Here are relevant snippets of my code.

First my Store:

var nStore = Ext.create('Ext.data.Store', {
    storeId: 'people',
    fields: ['team', 'name', 'liste', 'sums'],
    data: [{
        team: 'TestTeam', name: 'TestPerson',
        liste: ['F', 'F', 'F', 'S', 'N', 'F', 'S',
            'S', 'S', 'F', 'F', 'F', 'S', 'A', 'N',
            'S', 'S', 'S', 'S', '', '', 'N', 'N',
            'N', 'S', 'S', 'N', 'S', 'F', 'N', 'N'],
        sums: [[7, 4, 0, 0, 0, 0, 0], [3, 0, 0, 0, 0]]
    }]
});

Then my column array where the renderer is:

var counter = 0;
for (var i = 0; i < Object.kws.length; i++) {
    var DayOfMonth = [];
    var DayOfWeek = [];
    for (var j = 0; j < Object.kws[i].kwDays.length; j++) {
        var c = counter;
        DayOfMonth[j] = {
            text: '<span style="font-size: 87%;">' 
                    + Object.kws[i].kwDays[j].day 
                    + '.<br>' 
                    + Object.kws[i].kwDays[j].dayOfWeek
                    + '.</span>', sortable: false,
            draggable: false, menuDisabled: true,
            resizable: false, width: 40, align: 'center',
            renderer: function (value, meta, record) {
                return record.data.liste[c];

            }
        };
        counter++;
    }
}

The code is adapted and abridged.

Here is a picture of the result:

The Result

Normally the cells in the grid should show the counted element of the list in my Store.

Can anyone help me understand what I am doing wrong?


Solution

  • The problem is:

    In JavaScript, functions enclose variables which were defined in a scope outside of their own in such a way that they have a "living" reference to the variable, not a snapshot of its value at any particular time.

    Understanding variable capture by closures in Javascript/Node and How do JavaScript closures work?

    Since 'c' or 'counter' is fully incremented before the method that uses 'c' is invoked, the value of 'c' is always the highest value achieved in the for loop. To solve the issue you need to capture the value of 'c' at the point in time your renderer function is created. This code illustrates the issue and how to capture the value to achieve your desired effect:

    var counter = 0;
    var dayOfMonths = [];
    var dayOfMonthCaptured = [];
     for (var i = 0; i < 10; i++) {
      var c = counter;
      console.log(c);
      dayOfMonths.push(function () { 
        var index = c;
        //since counter is incremented fully before this method is called, you get the last value
        console.log(index); 
      });
      //here we pass the current value of c to a new function and capture its current value
      dayOfMonthCaptured.push((function (index) {
          return function () { 
            console.log(index); 
          };
       })(c));
      counter++;
    }
    //this won’t work
    for (day in dayOfMonths) {
      dayOfMonths[day]();
    }
    console.log("—————————");
    for (day in dayOfMonthCaptured) {
      dayOfMonthCaptured[day]();
    }