6

I have a grid in ext with some custom columns, and I want to be able to sort this column - I want to sort it by what is displayed inside of it, but really I just cannot figure out how to define a sorter for a column that will not be based on the dataIndex - I tried using a custom model, but I could not get that to work.

{
    text: 'Parent',
    dataIndex: 'Parent',
    renderer: function(value, meta, record) {
        var ret = record.raw.Parent;
        if (ret) {
            return ret.Name;
        } else {
            meta.tdCls = 'invisible';
            return record.data.Name;
        }
    },
    sortable: true
},
Tore
  • 1,236
  • 2
  • 11
  • 21
  • I think the reason neither of these solutions worked in my case is because I was using a Pageable Store, rather than an Ext.data.Store. Thank you both, your solutions both work when using an Ext.data.Store. – Tore Jul 23 '13 at 19:07

3 Answers3

4

You should be able to override the doSort method of the column. Here's the gist of it. I also created a working fiddle (http://jsfiddle.net/cfarmerga/LG5uA/). The fiddle uses the string length of a field as the property to sort on, but of course you could apply your own custom sort logic.

var grid = Ext.create('Ext.grid.Panel',{
    //...
    columns: [
        { text: 'name', dataIndex: 'name', sortable: true },
        {
            text: 'Custom',
            sortable : true,
            dataIndex: 'customsort',
            doSort: function(state) {
                var ds = this.up('grid').getStore();
                var field = this.getSortParam();
                ds.sort({
                    property: field,
                    direction: state,
                    sorterFn: function(v1, v2){
                        v1 = v1.get(field);
                        v2 = v2.get(field);
                        return v1.length > v2.length ? 1 : (v1.length < v2.length ? -1 : 0);
                    }
                });
            }
        }
    ]
   //....  
});
Chris Farmer
  • 24,974
  • 34
  • 121
  • 164
  • I set up the code block you stated, and when it failed to work, started console logging the various variables to make sure I was getting the correct thing. When I click on the column to sort, it correctly calls the doSort method. However, none of the console logs I put in the `ds.sort();` method ever ran, so I conclude that method never ran. Any idea what is happening here? Also, according to the API docs, shouldn't it be `ds.sort([{property...}]);` – Tore Jul 22 '13 at 19:47
  • I'm not sure how you would be adding console.log calls in the `ds.sort` method since you're not overriding that method. I just added a `console.log` to the `sorterFn` function and it gets called successfully. – Chris Farmer Jul 22 '13 at 20:08
  • Sorry, thats what I meant to say. I have `sorterFn: function(one, two) { console.log('one',one); console.log('two',two); one = one.get(field); two = two.get(field); return v1.length > v2.length ? 1 : (v1.length < v2.length ? -1 : 0); }` And the console does not show it! – Tore Jul 22 '13 at 20:25
  • Hmm. That's weird. I just updated the fiddle to show what I am trying. I see the console output during the sort. http://jsfiddle.net/LG5uA/5/ You won't see the function get called unless you click on the column header though, which will initiate the sort. – Chris Farmer Jul 22 '13 at 20:30
  • Right, and I have a console.log() in the `doSort();` method, which does execute every time I click on the column header – Tore Jul 22 '13 at 20:34
  • Do you see the console logging in the fiddle I created? Do you see it successfully sort by the string length? – Chris Farmer Jul 22 '13 at 20:41
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/33934/discussion-between-chris-farmer-and-user2544318) – Chris Farmer Jul 22 '13 at 20:44
  • This may work fine with a particular version of ExtJS but be aware that Column.doSort() is private and undocumented. So, in a future release, the contract could change or it could even go away. – David Easley Jun 09 '15 at 09:45
  • To further drive @DavidEasley's point home, it looks like `Ext.grid.colum.Column.doSort` was taken out in Ext JS 5. – incutonez Jun 29 '15 at 18:44
3

For Ext JS version 5, it looks like doSort was taken out, so I couldn't override that. Instead, I went the route of listening to the sortchange event, and from there, I used the Ext.data.Store.setSorters method. The code is a bit custom, and overly complex because of the data that I'm using, so keep that in mind (Fiddle here):

// grid class
initComponent: function() {
  ...
  this.on('sortchange', this.onSortChange, this);
},

onSortChange: function(container, column, direction, eOpts) {
  // check for dayColumnIndex
  if (column && column.dayColumnIndex !== undefined) {
    this.sortColumnByIndex(column.dayColumnIndex, direction);
  }
},

sortColumnByIndex: function(columnIndex, direction) {
  var store = this.getStore();
  if (store) {
    var sorterFn = function(rec1, rec2) {
      var sortValue = false;
      if (rec1 && rec2) {
        var day1;
        var daysStore1 = rec1.getDaysStore();
        if (daysStore1) {
          day1 = daysStore1.getAt(columnIndex);
        }
        var day2;
        var daysStore2 = rec2.getDaysStore();
        if (daysStore2) {
          day2 = daysStore2.getAt(columnIndex);
        }
        if (day1 && day2) {
          var val1 = day1.get('value');
          var val2 = day2.get('value');
          sortValue = val1 > val2 ? 1 : val1 === val2 ? 0 : -1;
        }
      }
      return sortValue;
    };
    if (direction !== 'ASC') {
      sorterFn = function(rec1, rec2) {
        var sortValue = false;
        if (rec1 && rec2) {
          var day1;
          var daysStore1 = rec1.getDaysStore();
          if (daysStore1) {
            day1 = daysStore1.getAt(columnIndex);
          }
          var day2;
          var daysStore2 = rec2.getDaysStore();
          if (daysStore2) {
            day2 = daysStore2.getAt(columnIndex);
          }
          if (day1 && day2) {
            var val1 = day1.get('value');
            var val2 = day2.get('value');
            sortValue = val1 < val2 ? 1 : val1 === val2 ? 0 : -1;
          }
        }
        return sortValue;
      };
    }
    store.setSorters([{
      sorterFn: sorterFn
    }]);
  }
}
incutonez
  • 3,241
  • 9
  • 43
  • 92
  • 1
    http://stackoverflow.com/a/25202392/1684254 THe private doSort method has been replaced by the sort method as discussed in post above. – Akin Okegbile Jan 21 '16 at 21:46
2

There is a convert method on the Ext.data.Model class that allows you to convert the data before it's being used. Then you can just specify this 'dataIndex' in your column and do a normal sort. The column will be sorted by that converted value. Here is the a sample model with just one field (Parent) and with it's corresponding conversion:

Ext.define('MyModel', {
    extend: 'Ext.data.Model',
    fields: [
        {name: 'Parent',   type: 'string', convert: sortParent},
        // other fields...
    ],
    sortParent: function(value, record) {
        var ret = record.raw.Parent;
        if (ret) {
            return ret.Name;
        } else {
            meta.tdCls = 'invisible';
            return record.data.Name;
        }
    }
});
  • I tried this approach, but I failed to get it working. I do not see the convert method, and I am not sure where to call the sortParent method from. – Tore Jul 22 '13 at 19:51
  • 1
    @JuanDanielFlores - your example works correctly with alternate data in place, but as originally posted, the fiddle's sorting is the same between the two columns. http://jsfiddle.net/LG5uA/57/ gives a better demonstration of it working. – David Millar Jun 17 '14 at 16:18