Reputation: 26
I'm trying to bind to form's dirty property but, looks like it is processed incorrectly
Please, check fiddle for code example and a description for the bug
https://fiddle.sencha.com/#fiddle/3ovk
// 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);
}
});
Key to reproduce - call lookup() before setting record to the form panel
I'm looking for the correct fix of the issue
Thanks!
Upvotes: 0
Views: 33
Reputation: 26
I was discussing the issue with Sencha Support team, and we came up with a quick fix for the issue by adding an override:
Ext.override(Ext.form.Panel, {
adjustChildDirtyCount: function (dirty) {
var me = this,
childDirtyState = me._childDirtyState;
if (childDirtyState) {
if (childDirtyState.ready) {
childDirtyState.counter += dirty ? 1 : -1;
// Fix - Counter should not be less than 0
if(childDirtyState.counter < 0){
childDirtyState.counter = 0
}
me.setDirty(!!childDirtyState.counter);
} else if (dirty) {
childDirtyState.ready = true
++childDirtyState.counter;
}
}
}
})
Looks like it works for me
Upvotes: 0
Reputation: 9819
First of all, in you current code, lookup
does not even find your form panel. Check this by adding console.log(f);
after var f = container.lookup...
. It will log null
.
This can be easily fixed by adding the referenceHolder: true,
configuration to the container
. After this it will already find the form panel within the container.
As for your question, my guess it is some kind of a race condition. The launch
function is called at the very early stage of starting an Ext JS application and the framework might not be completely ready with setting up the components. Usually lookup
is called from controllers or other places where the initialisation is already completed.
Try to add a button to the form panel and call lookup
from there, and remove the lookup
call from the launch
function.
buttons: [{
text: 'Lookup test',
handler: function (button) {
var f = button.up('formpanel').up('container').lookup('formref');
console.log(f);
}
}],
After this you will see that the dirty bind works as expected, even if you press the button, and from the console log you see that the lookup
finds the form panel.
Complete code with the suggested changes:
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
}],
});
var user = Ext.create('User', {
id: 'ABCD12345',
name: 'Conan',
age: 123,
phone: ''
});
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}'
}],
buttons: [{
text: 'Lookup',
handler: function (button) {
var f = button.up('formpanel').up('container').lookup('formref');
console.log(f);
}
}]
});
Ext.application({
name: 'Fiddle',
launch: function () {
var container = Ext.create({
referenceHolder: true,
xtype: 'container',
items: [form]
})
Ext.Viewport.add(container);
form.setRecord(user);
}
});
Upvotes: 0