Code Whisperer
Code Whisperer

Reputation: 1041

ExtJS Grid not refreshing after store update

I have a grid and a store. The store gets populated with some data - country - while the rest is empty. Once I receive more inputs I fill up the store with the inputs.

Assume that I have only 1 country in the store after the initial load.

Store:

feedTheGrid = new Ext.data.JsonStore({
    autoDestroy : true,
    autoSave : false,
    autoLoad : true,
    idProperty: 'country',
    root: 'root',
    totalProperty : 'totalcount',
    fields : ['country', 'towns'],
    proxy : new Ext.data.HttpProxy(new Ext.data.Connection({
        url : "country/searchCountries.action",
        method : 'POST',
        timeout : 300000
    }))
});

So the user inputs towns. I save a town in the array towns using push():

listeners: {
    'change': function() {
        if (feedTheGrid.getAt(0).towns === undefined) {
            feedTheGrid.getAt(0).towns = [];
        }
        feedTheGrid.getAt(0).towns.push(this.getValue());
        gridMonster.getView().refresh();
    }
}

I want the grid to update every time a new town is put in.

This is part of the column model I use for gridMonster:

{ header: "Town 1", width: 150, dataIndex: 'towns', 
  renderer: function(val) {
      if (val[0] != undefined) {
          return val[0];
      }
  }, sortable: true},
{ header: "Town 2", width: 150, dataIndex: 'towns',
  renderer: function(val) {
      if (val[1] != undefined) {
          return val[1];
      }
  }, sortable: true},  
{ header: "Town 3", width: 150, dataIndex: 'towns',
  renderer: function(val) {
      if (val[2] != undefined) {
          return val[2];
      }
  }, sortable: true}

The issue is that after a town is put in the grid never refreshes.

Some things I noticed so far:

The store gets updated with the new value when I check through Firebug. Also it seems the val that is given in renderer is always empty String, even after I push the new value into the array and refresh the grid view.

I am using ExtJS 3.3.1

I know its old so I am open to solutions that would work for 4.0+ and I can try to apply it to 3.3.1.

EDIT: Found the issue

Very subtle problem, spent hours trying to find what is the problem only to find out I was looking in the wrong place. The issue was in this line:

feedTheGrid.getAt(0).towns.push(this.getValue());

This line actually creates a new field towns as part of the record that you get using getAt(0). Using firebug to see if getAt(0).towns[0] is populated actually returns the value you pushed which is misleading.

ExtJS is not aware of this new field and it shouldn't be.

This line should be:

feedTheGrid.getAt(0).data.towns.push(this.getValue());

The trick is to point at the right place: .data. Javascript/ExtJS allows you to add new field without any warning because technically you are not doing anything wrong. Logically it creates a new field that does nothing.

@Lorenz Meyer I am able to display elements of the array using renderer while pointing at towns array in the column model.

Upvotes: 1

Views: 5589

Answers (3)

Code Whisperer
Code Whisperer

Reputation: 1041

Very subtle problem, spent hours trying to find what is the problem only to find out I was looking in the wrong place. The issue was in this line:

feedTheGrid.getAt(0).towns.push(this.getValue());

This line actually creates a new field towns as part of the record that you get using getAt(0). Using firebug to see if getAt(0).towns[0] is populated actually returns the value you pushed which is misleading.

ExtJS is not aware of this new field and it shouldn't be.

This line should be:

feedTheGrid.getAt(0).data.towns.push(this.getValue());

The trick is to point at the right place: .data. Javascript/ExtJS allows you to add new field without any warning because technically you are not doing anything wrong. Logically it creates a new field that does nothing.

@Lorenz Meyer I am able to display elements of the array using renderer while pointing at towns array in the column model.

Upvotes: 0

Lorenz Meyer
Lorenz Meyer

Reputation: 19915

There is a major misunderstanding about what a store and a grid are in ExtJs.

Both are just a representation of tabular data. A store is the representation in memory of a table, in order to get fast access to records filtering and more features. A grid is the visual representation of a table in the browser window.

Such a table could look like :

Id | Country | City
-------------------
1  | US      | NYC
2  | France  | Macon
3  | US      | Macon

First of all on one table row, you can only have one city. In tables, you cannot have an array in a single field. If you have more than one city, this is what rows are for.

Then, your idProperty cannot be the country. If it were, this would mean that countries are unique. Obviously, they aren't. There can be more than one city in a country. (cities cannot be the idProperty neither, because there exists more than one city with the same).

Now you certainly begin to understand, that feedTheGrid.getAt(0).towns.push(this.getValue()); makes no sense whatever. The towns column cannot be an array. You insert a new row with feedTheGrid.add({country: 'US', towns: 'LA'}).
At best the towns column can be a comma separated value, in which case, you update the store with

var record = feedTheGrid.getAt(0),
currentTowns = record.get('towns');
record.set('towns', currentTowns + ', ' + value)

The method set of the record does all the magic: It passes the update event to the grid in order to rerender it. Your push in addition to be wrong will not trigger the events necessary to update the view.

About the grid: The columns of your grid should be:

{ header: "Id", width: 150, dataIndex: 'id', sortable: true},
{ header: "Country", width: 150, dataIndex: 'country', sortable: true},  
{ header: "Town(s)", width: 150, dataIndex: 'towns', sortable: true}

Notes:

  • That listeners: looks really strange to me, but maybe it's just because the bigger picture is missing.
  • feedTheGrid is a strange name for a store. The store does not feed the data. It is tha data.
  • A renderer alway must return a value, else the cell will remain blank. Therefore your renderers cannot work.

Upvotes: 2

Thevs
Thevs

Reputation: 3253

In your renderers the val can not be an array. It's a simple variable. That's why your grid is not refreshing.

Upvotes: 1

Related Questions