incutonez
incutonez

Reputation: 3331

ExtJS 5: displayfield binding performance

I have a window that pops up for creating a new item... when I pass in the record for my bound fields, the dialog appears to lag significantly. The record is just a new record that I created, so it doesn't have any values associated to it, other than what the framework provides as defaults. In this example, I have 3 buttons:

It appears this performance issue has been addressed in the nightly builds for Ext JS 5 and 6, but I don't have time to upgrade to 6, and 5.1.3 isn't out yet... so basically, what am I doing wrong? Is there anything I can do to address this current issue (other than using the form)? Ideally I'd still be binding, as the table values are going to have to change dynamically.

Doing a little research, I came up with this SO thread, which does appear to alleviate some of the lag, if I change the displayfields to textfields, but I'd rather not do that, due to semantics.

Ext.define('HeaderView', {
  extend: 'Ext.panel.Panel',
  alias: 'widget.headerView',

  bodyPadding: '0 15',
  border: true,
  collapsible: true,
  layout: {
    type: 'hbox',
    align: 'stretch'
  },
  items: [{
    xtype: 'container',
    layout: {
      type: 'vbox',
      align: 'stretch'
    },
    margin: '0 20 0 0',
    width: 515,
    items: [{
      xtype: 'container',
      layout: {
        type: 'hbox',
        align: 'stretch'
      },
      height: 70,
      hidden: true,
      bind: {
        hidden: '{isNew}'
      },
      items: [{
        xtype: 'container',
        flex: 1,
        layout: {
          type: 'vbox',
          align: 'stretch'
        },
        defaults: {
          xtype: 'displayfield',
          flex: 1,
          cls: 'tightened-form-field'
        },
        items: [{
          fieldLabel: 'Status',
          bind: {
            value: '{currentRecord.Status}'
          }
        }, {
          fieldLabel: 'Condition',
          bind: {
            value: '{currentRecord.StatusCombinedCondition}'
          }
        }, {
          fieldLabel: 'Type',
          bind: {
            value: '{currentRecord.Type}'
          }
        }]
      }, {
        xtype: 'container',
        flex: 1,
        layout: {
          type: 'vbox',
          align: 'stretch'
        },
        defaults: {
          xtype: 'displayfield',
          flex: 1,
          cls: 'tightened-form-field'
        },
        items: [{
          fieldLabel: 'Status Date',
          bind: {
            value: '{currentRecord.StatusDate}'
          }
        }, {
          fieldLabel: 'Create Date',
          bind: {
            value: '{currentRecord.CreateDate}'
          }
        }, {
          fieldLabel: 'Number',
          bind: {
            value: '{currentRecord.Number}'
          }
        }]
      }]
    }, {
      xtype: 'container',
      flex: 1,
      layout: {
        type: 'vbox',
        align: 'stretch'
      },
      defaults: {
        xtype: 'container',
        cls: 'summary-table',
        layout: {
          type: 'hbox',
          align: 'stretch'
        },
        defaults: {
          flex: 1,
          xtype: 'displayfield',
          cls: 'right-align-field'
        }
      },
      items: [{
        cls: '',
        items: [{
          value: '',
          cls: 'table-header'
        }, {
          value: 'Missed',
          cls: 'table-header status-text-error-background'
        }, {
          value: 'Offered',
          cls: 'table-header status-text-success-background'
        }, {
          value: 'Difference',
          cls: 'table-header status-text-new-background'
        }, {
          value: 'Old Total',
          cls: 'table-header status-text-error-background'
        }, {
          value: 'New Total',
          cls: 'table-header status-text-success-background'
        }]
      }, {
        items: [{
          value: 'Total'
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.ValueTotal1}'
          }
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.ValueTotal2}'
          }
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.ValueTotal3}'
          }
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.ValueTotal4}'
          }
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.ValueTotal5}'
          }
        }]
      }, {
        items: [{
          value: '# Things'
        }, {
          bind: {
            value: '{currentRecord.CountTotal1}'
          }
        }, {
          bind: {
            value: '{currentRecord.CountTotal2}'
          }
        }, {
          bind: {
            value: '{currentRecord.CountTotal3}'
          }
        }, {
          bind: {
            value: '{currentRecord.CountTotal4}'
          }
        }, {
          bind: {
            value: '{currentRecord.CountTotal5}'
          }
        }]
      }, {
        items: [{
          value: 'Points'
        }, {
          bind: {
            value: '{currentRecord.Points1}'
          }
        }, {
          bind: {
            value: '{currentRecord.Points2}'
          }
        }, {
          bind: {
            value: '{currentRecord.Points3}'
          }
        }, {
          bind: {
            value: '{currentRecord.Points4}'
          }
        }, {
          bind: {
            value: '{currentRecord.Points5}'
          }
        }]
      }, {
        items: [{
          value: 'Cost'
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.Cost1}'
          }
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.Cost2}'
          }
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.Cost3}'
          }
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.Cost4}'
          }
        }, {
          renderer: Ext.util.Format.usMoney,
          bind: {
            value: '{currentRecord.Cost5}'
          }
        }]
      }]
    }]
  }, {
    xtype: 'container',
    maxWidth: 450,
    flex: 1,
    layout: {
      type: 'vbox',
      align: 'stretch'
    },
    items: [{
      xtype: 'textarea',
      name: 'Comment',
      fieldLabel: 'Comment',
      flex: 1,
      bind: {
        disabled: '{!isNew}'
      }
    }, {
      xtype: 'textarea',
      name: 'RejectReason',
      fieldLabel: 'Reject Comment',
      height: 70,
      flex: 1,
      hidden: true,
      bind: {
        hidden: '{isNew}',
        disabled: '{!isNew}'
      }
    }]
  }]
});
Ext.define('HeaderViewForm', {
  extend: 'Ext.form.Panel',
  alias: 'widget.headerViewForm',

  bodyPadding: '0 15',
  border: true,
  collapsible: true,
  layout: {
    type: 'hbox',
    align: 'stretch'
  },
  items: [{
    xtype: 'container',
    layout: {
      type: 'vbox',
      align: 'stretch'
    },
    margin: '0 20 0 0',
    width: 515,
    items: [{
      xtype: 'container',
      layout: {
        type: 'hbox',
        align: 'stretch'
      },
      height: 70,
      hidden: true,
      bind: {
        hidden: '{isNew}'
      },
      items: [{
        xtype: 'container',
        flex: 1,
        layout: {
          type: 'vbox',
          align: 'stretch'
        },
        defaults: {
          xtype: 'displayfield',
          flex: 1,
          cls: 'tightened-form-field'
        },
        items: [{
          fieldLabel: 'Status',
            name: 'Status'
        }, {
          fieldLabel: 'Condition',
            name: 'StatusCombinedCondition'
        }, {
          fieldLabel: 'Type',
            name: 'Type'
        }]
      }, {
        xtype: 'container',
        flex: 1,
        layout: {
          type: 'vbox',
          align: 'stretch'
        },
        defaults: {
          xtype: 'displayfield',
          flex: 1,
          cls: 'tightened-form-field'
        },
        items: [{
          fieldLabel: 'Status Date',
            name: 'StatusDate'
        }, {
          fieldLabel: 'Create Date',
            name: 'CreateDate'
        }, {
          fieldLabel: 'Number',
            name: 'Number'
        }]
      }]
    }, {
      xtype: 'container',
      flex: 1,
      layout: {
        type: 'vbox',
        align: 'stretch'
      },
      defaults: {
        xtype: 'container',
        cls: 'summary-table',
        layout: {
          type: 'hbox',
          align: 'stretch'
        },
        defaults: {
          flex: 1,
          xtype: 'displayfield',
          cls: 'right-align-field'
        }
      },
      items: [{
        cls: '',
        items: [{
          value: '',
          cls: 'table-header'
        }, {
          value: 'Missed',
          cls: 'table-header status-text-error-background'
        }, {
          value: 'Offered',
          cls: 'table-header status-text-success-background'
        }, {
          value: 'Difference',
          cls: 'table-header status-text-new-background'
        }, {
          value: 'Old Total',
          cls: 'table-header status-text-error-background'
        }, {
          value: 'New Total',
          cls: 'table-header status-text-success-background'
        }]
      }, {
        items: [{
          value: 'Total'
        }, {
          renderer: Ext.util.Format.usMoney,
            name: 'ValueTotal1'
        }, {
          renderer: Ext.util.Format.usMoney,
            name: 'ValueTotal2'
        }, {
          renderer: Ext.util.Format.usMoney,
            name: 'ValueTotal3'
        }, {
          renderer: Ext.util.Format.usMoney,
            name: 'ValueTotal4'
        }, {
          renderer: Ext.util.Format.usMoney,
            name: 'ValueTotal5'
        }]
      }, {
        items: [{
          value: '# Things'
        }, {
            name: 'CountTotal1'
        }, {
            name: 'CountTotal2'
        }, {
            name: 'CountTotal3'
        }, {
            name: 'CountTotal4'
        }, {
            name: 'CountTotal5'
        }]
      }, {
        items: [{
          value: 'Points'
        }, {
            name: 'Points1'
        }, {
            name: 'Points2'
        }, {
            name: 'Points3'
        }, {
            name: 'Points4'
        }, {
            name: 'Points5'
        }]
      }, {
        items: [{
          value: 'Cost'
        }, {
            name: 'Cost1',
          renderer: Ext.util.Format.usMoney
        }, {
            name: 'Cost2',
          renderer: Ext.util.Format.usMoney
        }, {
            name: 'Cost3',
          renderer: Ext.util.Format.usMoney
        }, {
            name: 'Cost4',
          renderer: Ext.util.Format.usMoney
        }, {
            name: 'Cost5',
          renderer: Ext.util.Format.usMoney
        }]
      }]
    }]
  }, {
    xtype: 'container',
    maxWidth: 450,
    flex: 1,
    layout: {
      type: 'vbox',
      align: 'stretch'
    },
    items: [{
      xtype: 'textarea',
      name: 'Comment',
      fieldLabel: 'Comment',
      flex: 1,
      bind: {
        disabled: '{!isNew}'
      }
    }, {
      xtype: 'textarea',
      name: 'RejectReason',
      fieldLabel: 'Reject Comment',
      height: 70,
      flex: 1,
      hidden: true,
      bind: {
        hidden: '{isNew}',
        disabled: '{!isNew}'
      }
    }]
  }]
});

Ext.define('MyModel', {
    extend: 'Ext.data.Model',
    fields: [{
        name: 'Status',
        type: 'string'
    }, {
        name: 'StatusCombinedCondition',
        type: 'string'
    }, {name: 'Type', type: 'string'},
{name: 'StatusDate', type: 'string'},
{name: 'CreateDate', type: 'string'},
{name: 'Number', type: 'string'},
{name: 'ValueTotal1', type: 'string'},
{name: 'ValueTotal2', type: 'string'},
{name: 'ValueTotal3', type: 'string'},
{name: 'ValueTotal4', type: 'string'},
{name: 'ValueTotal5', type: 'string'},
{name: 'CountTotal1', type: 'string'},
{name: 'CountTotal2', type: 'string'},
{name: 'CountTotal3', type: 'string'},
{name: 'CountTotal4', type: 'string'},
{name: 'CountTotal5', type: 'string'},
{name: 'Points1', type: 'string'},
{name: 'Points2', type: 'string'},
{name: 'Points3', type: 'string'},
{name: 'Points4', type: 'string'},
{name: 'Points5', type: 'string'},
{name: 'Cost1', type: 'string'},
{name: 'Cost2', type: 'string'},
{name: 'Cost3', type: 'string'},
{name: 'Cost4', type: 'string'},
{name: 'Cost5', type: 'string'},
{name: 'Comment', type: 'string'},
{name: 'RejectReason', type: 'string'}]
});

Ext.define('MyController', {
    extend: 'Ext.app.ViewController',
    alias: 'controller.myView',
    init: function() {
        var me = this;
        // push onto call stack to let view model breathe
        setTimeout(function() {
            me.getView().setLoading(false);
        }, 1)
    }
})

Ext.application({
    name : 'Fiddle',

    launch : function() {
        Ext.create('Ext.button.Button', {
            text: 'currentRecord',
            renderTo: Ext.getBody(),
            listeners: {
                click: function() {
                    Ext.create('Ext.window.Window', {
                        height: 500,
                        width: 500,
                        autoShow: true,
                        layout: 'fit',
                        items: [{
                            xtype: 'headerView',
                            height: 500,
                            width: 500
                        }],
                        listeners: {
                            afterrender: function(view) {
                                view.setLoading(true)
                            }
                        },
                        viewModel: {
                            data: {
                                isNew: false,
                                currentRecord: Ext.create('MyModel')
                            }
                        },
                        controller: 'myView'
                    })
                }
            }
        })
        Ext.create('Ext.button.Button', {
            text: 'no currentRecord',
            renderTo: Ext.getBody(),
            listeners: {
                click: function() {
                    Ext.create('Ext.window.Window', {
                        height: 500,
                        width: 500,
                        autoShow: true,
                        layout: 'fit',
                        items: [{
                            xtype: 'headerView',
                            height: 500,
                            width: 500
                        }],
                        listeners: {
                            afterrender: function(view) {
                                view.setLoading(true)
                            }
                        },
                        viewModel: {
                            data: {
                                isNew: false
                            }
                        },
                        controller: 'myView'
                    })
                }
            }
        })
        Ext.create('Ext.button.Button', {
            text: 'currentRecord form',
            renderTo: Ext.getBody(),
            listeners: {
                click: function() {
                    var myModel = Ext.create('MyModel');
                    console.log(myModel)
                    Ext.create('Ext.window.Window', {
                        height: 500,
                        width: 500,
                        autoShow: true,
                        layout: 'fit',
                        items: [{
                            xtype: 'headerViewForm',
                            height: 500,
                            width: 500,
                            bind: {
                                currentRecord: '{currentRecord}'
                            },
                            setCurrentRecord: function(record) {
                                console.log(record)
                                if (record) {
                                    this.loadRecord(record)
                                }
                            }
                        }],
                        listeners: {
                            afterrender: function(view) {
                                view.setLoading(true)
                            }
                        },
                        viewModel: {
                            data: {
                                isNew: false,
                                currentRecord: myModel
                            }
                        },
                        controller: 'myView'
                    })
                }
            }
        })
    }
});

Upvotes: 0

Views: 1089

Answers (2)

incutonez
incutonez

Reputation: 3331

Another solution I came up with was based on this SO thread, but I just extended on the css there... removed the borders, cursor, etc. It's not ideal, but it definitely gets the job done.

Ext.define('FauxDisplayField', {
    extend: 'Ext.form.field.Text',
    alias: 'widget.fauxDisplayField',
    readOnly: true,
    tabIndex: -1,
    componentCls: 'faux-display-field'
});

.faux-display-field .x-form-trigger-wrap {
    border: none;
}

.faux-display-field input {
    text-shadow: 0 0 0 black; /* makes text show up without cursor */
    color: transparent; /* makes blinking cursor invisible */
    cursor: default;
    background-color: transparent;
    text-align: right;
}

Upvotes: 1

incutonez
incutonez

Reputation: 3331

One of the Sencha devs suggested this as a solution:

Ext.define('Foo', {
    override: 'Ext.util.Scheduler',

    notify: function() {
        Ext.suspendLayouts();
        this.callParent();
        Ext.resumeLayouts(true);
    }
});

Upvotes: 0

Related Questions