使用ExtJs 5.1.0,Chrome 44.0 +
查看我遇到间歇性问题,当使用CellEditor修改网格面板的内容时,在排序其中一列后尝试编辑单元格时会引发错误。
这是堆栈跟踪:
Uncaught TypeError: Cannot read property 'parentNode' of nullExt.define.onShow @ CellEditor.js?ver=911111541:147
Ext.define.show @ Component.js?ver=911111541:5104
Ext.define.startEdit @ Editor.js?ver=911111541:333
Ext.Base.Base.addMembers.callParent @ Base.js?ver=911111541:1255
Ext.define.startEdit @ CellEditor.js?ver=911111541:132
Ext.define.showEditor @ CellEditing.js?ver=911111541:536
Ext.define.startEdit @ CellEditing.js?ver=911111541:479
Ext.define.onCellClick @ Editing.js?ver=911111541:446
fire @ Event.js?ver=911111541:387
doFireEvent @ Observable.js?ver=911111541:654
prototype.doFireEvent @ EventDomain.js?ver=911111541:293
fireEventArgs @ Observable.js?ver=911111541:587
fireEvent @ Observable.js?ver=911111541:540
Ext.define.processItemEvent @ Table.js?ver=911111541:2445
Ext.define.processUIEvent @ View.js?ver=911111541:619
Ext.define.handleEvent @ View.js?ver=911111541:562
fire @ Event.js?ver=911111541:387
Ext.define.fire @ Dom.js?ver=911111541:367
Ext.define.publish @ Dom.js?ver=911111541:339
Ext.define.doDelegatedEvent @ Dom.js?ver=911111541:398
Ext.define.onDelegatedEvent @ Dom.js?ver=911111541:379
(anonymous function) @ Function.js?ver=911111541:145
CellEditor的onShow方法中的相关代码位:
if (me.el.dom.parentNode !== me.renderTo) {
me.renderTo.appendChild(me.el.dom);
}
网格本身是空的开始。它有一个与之关联的工具栏,其中包含允许您添加/复制/删除行的按钮。
这是一个表示此设置的小提琴(但无法在小提琴中重现):
https://fiddle.sencha.com/#fiddle/top
重现的步骤大致如下:
In Chrome 44.0 (Not seen in other browsers)
1) Add a new row, fill in the fields
2) Sort on field2
3) Add three new rows
4) Add a value to one of the new rows under column for field 2
5) Sort on field2
6) Try to edit a cell in the field2 column
此时,大约10%的时间会出现错误并且网格将被破坏。如果在步骤6中问题未被复制,您可以导航到浏览器中的另一个选项卡,等待几分钟,返回网格并尝试编辑它,问题就会发生。这几乎是100%的再现率。
请注意,这些步骤并不准确。例如,您可以使用第一列来尝试此操作。或者添加一些任意数量的行。你玩网格的时间越长并尝试排序,你就越有可能看到错误。
如果您看到错误,然后再次尝试编辑网格中的任何单元格,您将收到此错误:
Uncaught TypeError: Cannot read property 'style' of nullExt.define.setSize @ CompositeElementLite.js?ver=911111541:1674
Ext.define.setSize @ Component.js?ver=911111541:4922
Ext.define.setWidth @ Component.js?ver=911111541:5033
Ext.define.realign @ CellEditor.js?ver=911111541:282
Ext.define.startEdit @ Editor.js?ver=911111541:334
Ext.Base.Base.addMembers.callParent @ Base.js?ver=911111541:1255
Ext.define.startEdit @ CellEditor.js?ver=911111541:132
Ext.define.showEditor @ CellEditing.js?ver=911111541:536
Ext.define.startEdit @ CellEditing.js?ver=911111541:479
Ext.define.onCellClick @ Editing.js?ver=911111541:446
fire @ Event.js?ver=911111541:387
doFireEvent @ Observable.js?ver=911111541:654
prototype.doFireEvent @ EventDomain.js?ver=911111541:293
fireEventArgs @ Observable.js?ver=911111541:587
fireEvent @ Observable.js?ver=911111541:540
Ext.define.processItemEvent @ Table.js?ver=911111541:2445
Ext.define.processUIEvent @ View.js?ver=911111541:619
Ext.define.handleEvent @ View.js?ver=911111541:562
fire @ Event.js?ver=911111541:387
Ext.define.fire @ Dom.js?ver=911111541:367
Ext.define.publish @ Dom.js?ver=911111541:339
Ext.define.doDelegatedEvent @ Dom.js?ver=911111541:398
Ext.define.onDelegatedEvent @ Dom.js?ver=911111541:379(anonymous function) @ Function.js?ver=911111541:145
以下是我的一些代码,可能相关或不相关:
在initComponent函数中,我首先创建cellediting插件:
this._cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1,
disabled: this.getDisableEdit()
});
稍后将为网格本身将其分配给插件配置项:
plugins: [
this._cellEditing
]
这是添加按钮的逻辑:
// Create a record instance through the ModelManager
var newRow = new BidPackageSchedulesGridPanel.Model();
this.getStore().add(newRow);
if (moveToRow) {
this._cellEditing.startEdit(newRow, 1);
}
模型本身:
Ext.define('BidPackageSchedulesGridPanel.Model', {
extend: "Ext.data.Model",
fields: [
FieldIds.FIELD_1,
FieldIds.FIELD_2,
FieldIds.FIELD_3,
// Must specify a default value of "" in order to display null values correctly in IE.
{
name: FieldIds.QUANTITY,
type: 'string',
defaultValue: ""
}
],
validators: {
FIELD_1: [presenceValidator, 'length'],
FIELD_2: 'length',
FIELD_3: 'length',
QUANTITY: presenceValidator
},
identifier: 'sequential'
});
在网格面板的配置中初始化商店的位置:
store: {
model: Ext.create("BidPackageSchedulesGridPanel.Model"),
data: []
},
我们使用数据提供程序加载商店数据。
前三个字段的列是使用以下逻辑创建的:
_createColumn: function(label, dataIndex) {
var column = {
text: Ext.String.htmlEncode(label),
dataIndex: dataIndex,
sortable: this.isJobSchedule(),
draggable: false,
flex: 1
};
if (this.isJobSchedule() || dataIndex == FieldIds.FIELD_3) {
Ext.apply(column, {
editor: {
xtype: 'textfield'
}
});
}
return column;
},
如果我可以提供任何其他代码,请告诉我。我怀疑这是Ext中的一个错误,我已经向他们提交了一个错误报告,但如果有必要,现在就可以解决这个问题。
谢谢!
答案 0 :(得分:1)
我已经解决了这个问题,然而,它可能会产生不可预见的后果。我在CellEditor.js中注意到了这个注释,在setGridMethod:
中 // On view refresh, we need to copy our DOM into the detached body to prevent it from being garbage collected.
view.on(viewListeners);
事实上,我在GarbageCollector中设置了一个断点,并看到该单元格编辑器节点被不正确地垃圾收集。我将垃圾收集器间隔(在GarbageCollector.js中)设置为10秒。将数据添加到网格并进行排序,并且十秒钟窗口通过后,问题在100%的时间内都是可重现的。它被垃圾收集,因为它的父节点为null(参见Ext.isGarbage中的AND条件)。
在CellEditor.onViewRefresh()函数中,对于被垃圾收集的组件,此方法没有给组件一个父节点,然后它被垃圾收集。
我改变了
} else if (!sorting) {
Ext.getDetachedBody().dom.appendChild(dom);
}
到
} else {
Ext.getDetachedBody().dom.appendChild(dom);
}
问题已经消失。我已经测试了网格编辑功能,似乎没有任何内容被破坏。