Best practice for overriding classes / properties in ExtJS?

For clarification: By real class modification I mean a intended permanent modification/extension of a class, which should always be done by extending a class. But it is not a temporary solution for just a specific problem (bug-fix, etc.).

You have at least four options how to override members of (Ext) Classes

  • prototype I guess is well known and allows you to override a member for all instances of a class. You can use it like

    Ext.view.View.prototype.emptyText = "";
    

    While you can't use it like

    // callParent is NOT allowed for prototype
    Ext.form.field.Text.prototype.setValue = function(val) {
        var me = this,
            inputEl = me.inputEl;
    
        if (inputEl && me.emptyText && !Ext.isEmpty(value)) {
            inputEl.removeCls(me.emptyCls);
            me.valueContainsPlaceholder = false;
        }
    
        me.callParent(arguments);
    
        me.applyEmptyText();
        return me;
    };
    

    Here's a JSFiddle

    This variant should not be used for real class modifications.

  • Ext.override does nearly the same then prototype but it fully applies to the ExtJS Class-system which allows you to use callParent()

    You can use it like

    // callParent is allowed for override
    Ext.override('Ext.form.field.Text', {
        setValue: function(val) {
            this.callParent(['In override']);
            return this;
        }
    });
    

    Here's a JSFiddle (c-p error fixed! Thanks to @nogridbag)

    Use case: I faced a (I think still existing) bad behavior of a radiogroup where ExtJS expect a object (key-value-pair) for correct setting of the value. But I have just one integer on my backend. I first applied a fix using Ext.override for the setValue() method and afterwards extend from radiogroup. There I just make a Key-Value-Pair from the given value and call the parent method with that.

    As @rixo mentioned this can be used for overriding a instance member. And may therefore be qualified for overriding even mixins (I never tested it myself)

    var panel = new Ext.Panel({ ... });
    Ext.override(panel, {
        initComponent: function () {
            // extra processing...
    
            this.callParent();
        }
    });
    

    This variant should not be used for real class modifications.

  • Extending a existent class to apply additional behavior & rendering. Use this variant to create a subtype that behaves different without loosing the original type.

    In the following example we extend the textfield with a method to change the labelcolor when setting a new value called setColored and override the setValue method to take care of removing a label color when setValue is called directly

    Ext.define('Ext.ux.field.Text',{
        extend: 'Ext.form.field.Text',
        widget: 'uxtextfield',
        setColored: function(val,color) {
            var me = this;
            if (me.settedCls) {
                me.removeCls(me.settedCls);
            }
            me.addCls(color);
            me.settedCls = color;
            me.setValue(val,true);
        },
        setValue: function(val,take) {
            var me = this;
            if (!take && me.settedCls) {
                me.removeCls(me.settedCls);
            }
            me.callParent(arguments);
            return me;
        }
    });
    

    Here's a JSFiddle

  • Overriding per instance will happen in really rare cases and might not be applicable to all properties. In such a case (where I don't have a example at hand) you have a single need for a different behavior and you might consider overriding a setting just per instance. Basically you do such things all times when you apply a config on class creation but most time you just override default values of config properties but you are also able to override properties that references functions. This completely override the implementation and you might allows don't have access to the basetype (if any exist) meaning you cannot use callParent. You might try it with setValue to see that it cannot be applied to a existing chain. But again, you might face some rare cases where this is useful, even when it is just while development and get reimplemented for productive. For such a case you should apply the override after you created the specific by using Ext.override as mentioned above.

    Important: You don't have access to the class-instance by calling this if you don't use Ext.override!

If I missed something or something is (no longer) correct, please comment or feel free to edit.

As commented by @Eric

None of these methods allow you to override mixins (such as Ext.form.field.Field). Since mixin functions are copied into classes at the time you define the class, you have to apply your overrides to the target classes directly


The answer by @sra is great and was very helpful to me in gaining a deeper understanding of the override functionality available in Ext, but it does not include the way that I most commonly implement overrides which looks something like this:

Ext.define('my.application.form.field.Text' {
    override: 'Ext.form.field.Text'
    getValue: function () {
        // your custom functionality here
        arguments[1] = false;

        // callParent can be used if desired, or the method can be 
        // re-written without reference to the original
        this.callParent(arguments)
    }
});

I'm still using Ext 5 so I would then load this file in my Application.js and add it to the requires array there which applies the override to the app globally. I think Ext 6 projects include an override folder and simply adding this file to that folder ensures the override is applied.


This is the only way that works for me in ExtJS 7.

Example:

app/desktop/overrides/Toast.js

Ext.define(null, {
    override: 'Ext.window.Toast',
    show : function () {
        this.callParent();
// Your custom code here...
    }
});