extjsextjs7formpanel

Ext.form.Panel is not correctly calculates dirty on consume record if lookup was used before


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!


Solution

  • 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