Ext.form.Panel调用lookup后绑定record时dirty属性计算错误
Ext.form.Panel dirty属性计算异常问题修复
问题现象
绑定Ext.form.Panel的dirty属性时发现计算异常:当在给表单面板设置record之前调用lookup()方法,且字段初始值为空字符串时,表单的dirty属性会被错误标记为true。
问题代码示例
// define model Ext.define('User', { extend: 'Ext.data.Model', fields: [ {name: 'name', type: 'string'}, {name: 'age', type: 'int', convert: null}, {name: 'phone', type: 'string'}, {name: 'alive', type: 'boolean', defaultValue: true, convert: null} ], }); // create new record, some filed should have empty string (ex. phone) var user = Ext.create('User', { id : 'ABCD12345', name : 'Conan', age : 123, phone: '' // phone: '123456789' // if the field is not empty, then dirty updated correctly }); // create basic form // (viewModel and binding just to check form dirty property) var form = Ext.create({ xtype: 'formpanel', viewModel: true, reference: 'formref', publishes: ["dirty"], trackResetOnLoad: true, items: [ { xtype: 'textfield', label: 'id', name: 'id' }, { xtype: 'textfield', label: 'name', name: 'name' }, { xtype: 'textfield', label: 'age', name: 'age' }, { xtype: 'textfield', label: 'phone', name: 'phone', }, { xtype: 'textfield', bubbleDirty: false, bind: '{formref.dirty}' }, ] }); Ext.application({ name : 'Fiddle', launch : function() { // render container and lookup for something to reproduce form durty bug var container = Ext.create({ xtype: 'container', items: [form] }) Ext.Viewport.add(container); // comment next line to check formref.dirty is set correctly var f = container.lookup('formref'); // lookup will call // beginSyncChildDirty: function() { // this._childDirtyState = { counter: 0, ready: false }; // }, // so, it initialize counter // as phone field value is not changed, it will call adjustChildDirtyCount with false // childDirtyState.counter += dirty ? 1 : -1; // now, the childDirtyState.counter is equal to -1 // and !!childDirtyState.counter equal to true // me.setDirty(!!childDirtyState.counter); // formref.dirty is now set to true form.setRecord(user); } });
问题根源
调用lookup('formref')会触发表单的beginSyncChildDirty方法,初始化_childDirtyState.counter为0。当给表单设置record后,空字符串的字段(如phone)会调用adjustChildDirtyCount(false),导致counter被减1变为-1。由于!!-1结果为true,最终表单的dirty属性被错误设置为true。
修复方案
方案1:调整调用顺序(最简单)
将lookup()调用放在setRecord()之后,确保表单先加载record数据,再初始化脏状态计数:
Ext.application({ name : 'Fiddle', launch : function() { var container = Ext.create({ xtype: 'container', items: [form] }) Ext.Viewport.add(container); // 先设置record,再调用lookup form.setRecord(user); var f = container.lookup('formref'); } });
方案2:重写adjustChildDirtyCount方法(避免计数器负数)
自定义FormPanel,重写adjustChildDirtyCount方法,确保计数器不会小于0:
Ext.define('FixDirtyFormPanel', { extend: 'Ext.form.Panel', adjustChildDirtyCount: function(dirty) { var state = this._childDirtyState; if (state) { state.counter += dirty ? 1 : -1; // 确保计数器不会小于0 state.counter = Math.max(state.counter, 0); this.setDirty(!!state.counter); } } }); // 创建表单时使用自定义xtype var form = Ext.create({ xtype: 'fixdirtyformpanel', viewModel: true, reference: 'formref', publishes: ["dirty"], trackResetOnLoad: true, items: [ // 原字段配置... ] });
方案3:手动重置脏状态(应急处理)
在设置record后手动重置表单和字段的脏状态:
form.setRecord(user); // 重置表单dirty为false form.setDirty(false); // 重置所有字段的原始值,确保后续脏状态判断准确 form.getFields().each(function(field) { field.resetOriginalValue(); });
内容的提问来源于stack exchange,提问作者A.Pokidin
相关产品推荐
相关产品推荐

