Wait! Looks like we don't have enough information to add this to bug database. Please follow this template bug format.
  1. #1
    Sencha Premium Member
    Join Date
    Sep 2010
    Posts
    98
    Vote Rating
    5
    plleeuwm is on a distinguished road

      0  

    Default callParent can be broken under two scenarios.

    callParent can be broken under two scenarios.


    [4.*] There are multiple cases that callParent doesn't handle. To be honest I don't think it should have to handle both of these scenarios but it should allow for overrides to be shared and work properly. We need to be able to define an override once and have it get applied to multiple classes cloning methods or sharing method instances mess up callParent calls.


    REQUIRED INFORMATION
    Ext version tested:
    • > Ext 4.*
    Test Case:
    Scenario 1:
    Have an override share a function that has a callParent
    Code:
    //Sharing the same method messes up the $previous property
    Code:
    var initComponent = function() {
            console.log(1)
            this.callParent();
    }
    
    
    Ext.define('Ext.overrides.Component',{
        override: 'Ext.Component',
        initComponent: initComponent
    })
    
    
    Ext.define('Ext.overrides.Component',{
        override: 'Ext.Component',
         initComponent: initComponent
    })
    
    
    Ext.define('Ext.overrides.Component',{
        override: 'Ext.Component',
         initComponent: initComponent
    })

    >new Ext.Component()

    >1


    Scenario 2 don't share the method but clone it instead


    Code:
    //Cloning the method makes callParent not handle the caller property
    // and in turn callParent thinks $previous is undefined even though it isn't
    Code:
    var initComponent = function() {
            console.log(1)
            this.callParent();
    }
    
    
    Ext.define('Ext.overrides.Component',{
        override: 'Ext.Component',
        initComponent: Ext.clone(initComponent)
    })
    
    
    Ext.define('Ext.overrides.Component',{
        override: 'Ext.Component',
         initComponent: Ext.clone(initComponent)
    })
    
    
    Ext.define('Ext.overrides.Component',{
        override: 'Ext.Component',
         initComponent: Ext.clone(initComponent)
    })

    >new Ext.Component()

    >1


    Working code:
    Code:
    Ext.define('Ext.overrides.Component',{
        override: 'Ext.Component',
        initComponent: function() {
            console.log(1)
            this.callParent();
        }
    })
    
    
    Ext.define('Ext.overrides.Component',{
        override: 'Ext.Component',
        initComponent: function() {
            console.log(1)
            this.callParent();
        }
    })
    
    
    Ext.define('Ext.overrides.Component',{
        override: 'Ext.Component',
        initComponent: Ext.clone(function() {
            console.log(1)
            this.callParent();
        })
    })

    >new Ext.Component()

    >1

    >1

    >1




  2. #2
    Sencha - Senior Forum Manager mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    37,347
    Vote Rating
    846
    mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute

      0  

    Default


    What is the use case for sharing a single initComponent method?
    Mitchell Simoens @SenchaMitch
    Sencha Inc, Senior Forum Manager
    ________________
    Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
    https://github.com/mitchellsimoens

    Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/

    Need more help with your app? Hire Sencha Services services@sencha.com

    Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is in print!

    When posting code, please use BBCode's CODE tags.

  3. #3
    Touch Premium Member
    Join Date
    Nov 2010
    Location
    Chicago
    Posts
    1,340
    Vote Rating
    131
    LesJ is a name known to all LesJ is a name known to all LesJ is a name known to all LesJ is a name known to all LesJ is a name known to all LesJ is a name known to all

      0  

    Default


    Quote Originally Posted by mitchellsimoens View Post
    What is the use case for sharing a single initComponent method?
    Also, cloning a function returns the same function, so what's the point of cloning?


    Code:
    var fn = function(){};
    fn === Ext.clone(fn); // true

  4. #4
    Sencha Premium Member
    Join Date
    Sep 2010
    Posts
    98
    Vote Rating
    5
    plleeuwm is on a distinguished road

      0  

    Default


    Use case: We have a 200+ line long override that we want apply it to Ext.form.field.Text, Ext.form.CheckboxGroup, one of our custom fields (that doesn't extend from Text of Checkbox group) and any other custom field in the future if need be.

  5. #5
    Sencha Premium Member
    Join Date
    Sep 2010
    Posts
    98
    Vote Rating
    5
    plleeuwm is on a distinguished road

      0  

    Default


    Quote Originally Posted by LesJ View Post
    Also, cloning a function returns the same function, so what's the point of cloning?


    Code:
    var fn = function(){};
    fn === Ext.clone(fn); // true
    There is a problem with shared instances hence the cloning. A cloned object should not return the same instance. For the example I assumed that Ext.clone(fn) would be equivalent to Ext.Function.clone(fn) apparently it is not. It is still a problem though. Excuse my formatting:

    Code:
    var initComponent = function() {        console.log(1)        this.callParent();}Ext.define('Ext.overrides.Component',{    override: 'Ext.Component',    initComponent: Ext.Function.clone(initComponent)})Ext.define('Ext.overrides.Component',{    override: 'Ext.Component',     initComponent: Ext.Function.clone(initComponent)})Ext.define('Ext.overrides.Component',{    override: 'Ext.Component',     initComponent: Ext.Function.clone(initComponent)})
    new Ext.Component()
    >1

    Code:
    Ext.Function.clone(Ext.emptyFn) === Ext.emptyFn
    > false

  6. #6
    Sencha - Ext JS Dev Team evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    17,006
    Vote Rating
    650
    evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute

      0  

    Default


    I'm not really sure I see the point of your test case.

    You're:
    1) Defining the same override name 3 times
    2) You're overriding the same function, with the same function reference 3 times

    I realise it may be for the sake of demonstrating something, but in it's current form it's quite confusing as to what you're trying to achieve.
    Evan Trimboli
    Sencha Developer
    Twitter - @evantrimboli
    Don't be afraid of the source code!

  7. #7
    Sencha Premium Member
    Join Date
    Sep 2010
    Posts
    98
    Vote Rating
    5
    plleeuwm is on a distinguished road

      0  

    Default


    Quote Originally Posted by evant View Post
    I'm not really sure I see the point of your test case.

    You're:
    1) Defining the same override name 3 times
    2) You're overriding the same function, with the same function reference 3 times

    I realise it may be for the sake of demonstrating something, but in it's current form it's quite confusing as to what you're trying to achieve.
    What is confusing about the test case? The problem is titled there are two scenarios which callParent can be broken. The test case is demonstrating that callParent doesn't work in all of those scenarios. If it did work it would >1 >1 >1 would be logged to the console but only >1 does. It actually doesn't matter if is the same override, all it needs to be broken are is to override a method that has a callParent in it with a cloned function or the same instance.

    Quote Originally Posted by plleeuwm View Post
    Use case: We have a 200+ line long override that we want apply it to Ext.form.field.Text, Ext.form.CheckboxGroup, one of our custom fields (that doesn't extend from Text of Checkbox group) and any other custom field in the future if need be.

  8. #8
    Sencha Premium Member
    Join Date
    Sep 2010
    Posts
    98
    Vote Rating
    5
    plleeuwm is on a distinguished road

      0  

    Default


    What more info is needed? I've provided use cases, expected results and ways to reproduce the problem and this obviously isn't a browser or OS specific issue.

    I can provide two more use cases related to the same problems.

    This works:

    Code:
    Ext.define('MyObject', {
        log: function() {
            console.log(0);
        }
    });
    
    
    Ext.override(MyObject, {
        log:function(num) {
            console.log(1);
            this.callParent();
        }
    });
    
    
    Ext.override(MyObject, {
        log: (function() {
            return function() {
                console.log(2);
                this.callParent();
            }
        })()
    });
    new MyObject().log()
    > 2
    > 1
    > 0

    These don't:

    Code:
    Ext.define('MyObject', {
        log: function() {
            console.log(0);
        }
    });
    
    
    Ext.override(MyObject, {
        log:function(num) {
            console.log(1);
            this.callParent();
        }
    });
    
    
    Ext.override(MyObject, {
        log:Ext.Function.createSequence(function(){
            console.log(2);
        }, function(){
            this.callParent();
        })
    });
    Code:
    Ext.define('MyObject', {
        log: function() {
            console.log(0);
        }
    });
    
    
    Ext.override(MyObject, {
        log:function(num) {
            console.log(1);
            this.callParent();
        }
    });
    
    
    
    
    Ext.override(MyObject, {
        log: Ext.pass(function(num) {
            console.log(num);
            this.callParent();
        }, [2])
    });
    new MyObject().log()
    >2
    >Error: this.callParent() was called but there's no such method (log) found in the parent class (Ext.Base)

  9. #9
    Sencha - Community Support Team mankz's Avatar
    Join Date
    Nov 2007
    Location
    Stockholm, Sweden
    Posts
    2,761
    Vote Rating
    108
    mankz is a name known to all mankz is a name known to all mankz is a name known to all mankz is a name known to all mankz is a name known to all mankz is a name known to all

      0  

    Default


    By adding that extra wrapping function, you're preventing the callParent method from functioning correctly. Is there any use case for your construct?

    This is what you end up getting:

    Code:
    MyObject.override({
        log: function(num) {
            function inner (num) {
                console.log(num);
                this.callParent();
            }
            inner.apply(this, arguments);
        }
    });

  10. #10
    Touch Premium Member
    Join Date
    Nov 2010
    Location
    Chicago
    Posts
    1,340
    Vote Rating
    131
    LesJ is a name known to all LesJ is a name known to all LesJ is a name known to all LesJ is a name known to all LesJ is a name known to all LesJ is a name known to all

      0  

    Default


    See if callSuper would be a better fit instead of callParent.

    I
    'd stay away from using the 'pass' and 'createSequence' functions to modify the methods.