【问题标题】:EXTJS 5 : How to sort grid column in EXT JS 5EXTJS 5:如何在 EXT JS 5 中对网格列进行排序
【发布时间】:2014-08-08 08:06:20
【问题描述】:

我最近将 EXT JS 的版本更新为 5,并且覆盖 doSort 函数不再起作用。有人知道怎么做吗?

覆盖示例:

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

编辑 1: 我只是尝试@tomgranerod 的解决方案,但 me.sortState 始终是“未定义”。 所以我这样做是为了更新我的变量:

    sort: function () {
        var me = this,
            grid = me.up('tablepanel'),
            store = grid.store;

        me.sortState = me.sortState === 'ASC' ? 'DESC' : 'ASC';

        Ext.suspendLayouts();
        me.sorting = true;
        store.sort({
            property: me.getSortParam(),
            direction: me.sortState,
            sortFn: function (v1, v2) {
                v1 = v1.get(field);
                v2 = v2.get(field);

                return v1.length > v2.length ? 1 : (v1.length < v2.length ? -1 : 0);
            }
        });
        delete me.sorting;
        Ext.resumeLayouts(true);
    }

但是 sortFn 函数永远不会被调用。我不知道为什么。 ===> !!!!它适用于 EXT JS 5.0.1,但永远不会调用 sortFin 函数。 !!!!

编辑 2: 这就是我想要的:

升序:

if (v1 and v2 are numbers) return v1 > v2;
else if (v1 is a number and v2 a string) return false;
else if (v1 is a string and v2 a number) return true;
else if (v1 and v2 are strings) return v1 > v2;

描述:

if (v1 and v2 are numbers) return v1 < v2;
else if (v1 is a number and v2 a string) return true;
else if (v1 is a string and v2 a number) return false;
else if (v1 and v2 are strings) return v1 < v2;

【问题讨论】:

  • 你不应该覆盖doSort,它是私有的。您应该期望它在升级时中断。你为什么不给网格提供一个分类器呢?见docs-origin.sencha.com/extjs/4.2.2/#!/api/…docs-origin.sencha.com/extjs/4.2.2/#!/example/grid/…
  • 如果您在fiddle.sencha.com/#home 发布一个运行(损坏)的示例,我可以看看
  • 感谢胡安的帮助。我尝试为煎茶小提琴树立一个榜样。
  • 这是小提琴:fiddle.sencha.com/#fiddle/8kk。我尝试对引用进行排序以具有此顺序 => ASC:1、12、103、T01、T02 和 DESC:T02、T01、103、12、1。但如果您测试排序并不会这样做。所以我必须覆盖排序。
  • 正确的方法是给你的Ext.data.Field提供一个分拣机,我会尽快看看,但可能要几个小时。顺便说一句,小提琴上的问题非常简单,看起来很容易

标签: javascript extjs extjs5


【解决方案1】:

您正在覆盖私有方法。所以几乎可以预料它会在一个主要版本之后中断。如果您查看http://docs.sencha.com/extjs/5.0.0/apidocs/source/Column2.html#Ext-grid-column-Column,您会发现不再有doSort 功能。

Ext 的建议方法是使用sortType config 可以采用一个函数将您的值转换为自然排序的值,通常最简单的方法是将其转换为数字。所以如果你想要一些稍微不同的东西,你可以修改我发布的代码来做你想做的事情,而不用重写私有方法。

运行示例:https://fiddle.sencha.com/#fiddle/8km

var store = Ext.create('Ext.data.Store', {
    fields: [{
        name: 'ref',
        sortType: function(str)  {
            // Ext-JS requires that you return a naturally sortable value
            // not your typical comparator function.
            // The following code puts all valid integers in the range 
            // Number.MIN_SAFE_INTEGER and 0
            // And assumes the other values start with T and sorts 
            // them as positive integers               
            var parsed = parseInt(str, 10); 
            if ( isNaN( parsed ) ){
                return parseInt(str.substring(1), 10);
            } else {
                return Number.MIN_SAFE_INTEGER + parsed;
            }          
        }
    }],
    data: {
        'items': [
            {'ref': '1'},
            {'ref': '12'},
            {'ref': 'T0134'},
            {'ref': '121878'},
            {'ref': 'T0134343'},
            {'ref': 'T01POPI'},
            {'ref': '103'},
            {'ref': 'T01'}            
        ]
    },
    proxy: {
        type: 'memory',
        reader: {
            type: 'json',
            rootProperty: 'items'
        }
    }
});

Ext.create('Ext.grid.Panel', {
    title: 'Grid custom',
    store: store,
    columns: [{
        text: 'Reference',
        dataIndex: 'ref',
    }],
    height: 300,
    width: 400,
    renderTo: Ext.getBody()
});

如果您要重用此功能,请查看http://spin.atomicobject.com/2012/07/20/simple-natural-sorting-in-extjs/

/** Sort on string length  */
Ext.apply(Ext.data.SortTypes, {
    myCrazySorter: function (str) {
        // Same as above
    }
});

// And use it like
var store = Ext.create('Ext.data.Store', {
    fields: [{
        name: 'ref',
        sortType: 'myCrazySorter'
    }],

【讨论】:

  • 它有效,但不是我的模式。我编辑我的帖子来写我的模式。在我的第一篇文章中,这是一个例子。很抱歉模棱两可。
  • @MickaëlP 我通过示例向您展示了实现自定义排序的正确方法,并按照您的代码所示实现了它。您是否尝试实施您描述的算法?这似乎超出了问题的范围
  • @JuandMendes 我看到了你的例子,但这并不是我真正想要做的。我在帖子的第二次编辑中描述了我的模式。我不知道如何用你的方式实现我的排序?
  • @MickaëlP 我已将其修复为与您给我的套装一起使用。 Ext 没有提供比较器功能。你必须将你的价值观映射到自然可比的东西上。这应该足以让您找出问题所在,即使这不是您想要的。
  • @MickaëlP 我已经向他们投诉过一次,他们似乎不会改变这一点。如果您愿意,可以在商店中使用比较器。 docs.sencha.com/extjs/5.0.0/apidocs/#!/api/… 如果您希望它适用于多级排序和多列,那么使用它并不是那么简单,因为您只能为整个商店提供比较器,而不是特定于列的比较器
【解决方案2】:

ExtJS 5 中的 doSort 等价函数,在快速查看 Ext.grid.column.Column 的源代码后,似乎是 'sort'。我在这个例子中使用的 sortState 参数似乎是在 ExtJS 5.0.1 中引入的。

sort: function () {
            var me = this,
                grid = me.up('tablepanel'),
                direction,
                store = grid.store;

            direction = me.sortState === 'ASC' ? 'DESC' : 'ASC';

            Ext.suspendLayouts();
            me.sorting = true;
            store.sort({
                sorterFn: function (v1, v2) {
                    v1 = v1.get(me.getSortParam());
                    v2 = v2.get(me.getSortParam());

                    return v1.length > v2.length ? 1 : (v1.length < v2.length ? -1 : 0);
                },
                direction: direction
            });
            delete me.sorting;
            Ext.resumeLayouts(true);
        }

但是,Juan Mendes 描述的解决方案比重写内部排序函数更安全、更可行。

【讨论】:

  • @MickaëlP 请不要添加评论作为答案,或者评论答案,或者更新您的问题
  • 是的,但我尝试删除它但我没有成功:(对不起。
  • 嗯,这对我来说很好用。虽然我是在 v5.0.1(昨天刚刚发布)上测试过的,所以可能会有一些差异。
  • 我用的是5.0.0版本。 5.0.1 是否可以更好地解决我的问题?
  • @tomgranerod 你可以在这里看到问题:fiddle.sencha.com/#fiddle/8kk
【解决方案3】:

我终于找到了在排序过程中比较两条记录的方法:

1) 定义自定义列:

Ext.define('Eloi.grid.column.ReferenceColumn', {
    extend : 'Ext.grid.column.Column',

    alias  : 'widget.referencecolumn',

    config : {
        ascSorter  : null,
        descSorter : null
    },

    destroy : function() {
        delete this.ascSorter;
        delete this.descSorter;

        this.callParent();
    },

    /**
     * @param {String} state The direction of the sort, `ASC` or `DESC`
     */
    sort : function(state) {
        var me         = this,
            tablePanel = me.up('tablepanel'),
            store      = tablePanel.store,
            sorter     = this[state === 'ASC' ? 'getAscSorter' : 'getDescSorter']();

        Ext.suspendLayouts();
        this.sorting = true;

        store.sort(sorter, state, 'replace');

        delete this.sorting;
        Ext.resumeLayouts(true);
    },

    getAscSorter : function() {
        var sorter = this.ascSorter;

        if (!sorter) {
            sorter = new Ext.util.Sorter({
                sorterFn  : this.createSorter('ASC'),
                direction : 'ASC'
            });

            this.setAscSorter(sorter);
        }

        return sorter;
    },

    getDescSorter : function() {
        var sorter = this.ascSorter;

        if (!sorter) {
            sorter = new Ext.util.Sorter({
                sorterFn  : this.createSorter('DESC'),
                direction : 'DESC'
            });

            this.setAscSorter(sorter);
        }

        return sorter;
    },

    createSorter : function(state) {
        var dataIndex = this.dataIndex;

        return function(rec1, rec2) {
            var v1   = rec1.get(dataIndex),
                v2   = rec2.get(dataIndex),
                num1 = parseInt(v1),
                num2 = parseInt(v2),
                ret;

            if (num1 && num2) {
                ret = num1 > num2 ? 1 : (num1 < num2 ? -1 : 0);
            } else {
                if (!num1 && !num2) {
                    num1 = parseInt(v1.substr(1));
                    num2 = parseInt(v2.substr(1));

                    ret = num1 > num2 ? 1 : (num1 < num2 ? -1 : 0);
                }
                if (!num1) {
                    ret = 1;
                }
                if (!num2) {
                    ret = -1;
                }
            }

            if (state === 'DESC') {
                ret = ret * -1;
            }

            return ret;
        };
    }
});

2) 将新类型设置为网格中的列(使用别名),不要忘记正确设置所需的配置:

columns  : [
        {
            xtype     : 'referencecolumn',
            text      : 'Reference',
            dataIndex : 'ref',
            flex      : 1
        }
    ]

【讨论】:

  • 如果您使用多列排序,这仍然有效吗?此外,您应该在parseInt 的结果上使用isNaN,因为对于parseInt("0") 的布尔检查将失败。最后,建议您指定第二个参数 radix。文档说 始终指定此参数 以消除读者混淆并保证可预测的行为。当未指定基数时,不同的实现会产生不同的结果见developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 一种令人困惑的行为/不同结果的情况是 parseInt("077") 一些浏览器 (IE) 会将其视为八进制,因为您以 0 开头并返回 63。一些浏览器 (Chrome ) 将假定基数为 10 并返回 77
  • 另外,请记住,您正在覆盖私有方法,因此您几乎要求您的实现在未来的版本中中断:) 我对商店应用自定义排序器的建议是支持的 API。在接触 Ext 的隐私之前尝试一下:p
【解决方案4】:

你需要使用

sorterFn 不是 sortFn

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 2014-11-13
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多