1. #1
    Sencha User
    Join Date
    Feb 2012
    Location
    Copenhagen
    Posts
    32
    Answers
    1
    Vote Rating
    0
    Igor.Szyporyn is on a distinguished road

      0  

    Default Answered: A few questions about extending components

    Answered: A few questions about extending components


    Hello there Sencha users.

    I just bought Abdullah Al Mohammad's book "Ext JS 4 Plugin and Extension Development"

    When I extend an ext component like a textfield (well any component really) I never use the constructor method at all - I find it screws up my config initialization, but maybe I am just using it wrong.

    So a few questions here.

    Q: Is it same same if you use constructor or initComponent - as long as you do not use both at the same time?

    Q: Which is the "correct" way - constructor or initComponent? Or is that maybe dependent on your extension (assume a component here ofc)

    When I want stuff to happen in my extension (lets say as the component is rendered) I add events to the initComponent after callParent - but I see Abdullah uses a method directly on the class named "afterRender" - about this one or two questions also

    Q: Does a component have all its events accessible like this? Would I also be able to access a added method and expect that code to be executed as the component is added?

    Q: I highly assume that these methods are treated as a single occurrence?

    Q: Is it good or bad practice to use methods such as these? I do it like this instead (and in this example lies another question I have)

    Code:
    initComponent: function () {
    
      var i_cmp = this;
    
    
      i_cmp.initConfig(i_cmp.initialConfig);
    
    
      i_cmp.callParent();
    
    
      i_cmp.on({
        'afterrender': {
          fn: function (i_self) {
    
    
            i_self...paint me red and add DOM nodes
          }
        },
        single: true
      });
    }
    As I said - in this example of mine lies a few questions also.

    Q: As you can see I do not call .callParent(arguments) - is this wrong? I mean it can't hurt I guess to send empty arguments in, but I do not see why I should as I have yet to see any component I have extended send along arguments to initComponent.

    Some components you extend has a this.initConfig(this.initialConfig) happening somewhere along the line, and as such for these I do not call the initConfig - but I do do it if it is not done by any off the classes in the chain my new class inherits from.

    Q: What is the "correct" way to initialize the config object (as to get automatic getters and setters etc..)

    If anyone are up for the task - then could I get a simple simple example of an extended textfield using all the best practice for creating component classes?

    Thanks in advance...
    Last edited by Igor.Szyporyn; 17 Dec 2013 at 10:29 AM. Reason: bad title

  2. Quote Originally Posted by Igor.Szyporyn View Post
    Q: Is it same same if you use constructor or initComponent - as long as you do not use both at the same time?

    Q: Which is the "correct" way - constructor or initComponent? Or is that maybe dependent on your extension (assume a component here ofc)
    Theoretically either will work, but I almost always override initComponent rather than the constructor, since the config values are available on the component at that point so it's easy to reference and/or override them. For instance, something like this would work in initComponent, but not in a constructor (this.border would be undefined, and Ext.apply(this) would be overwritten by the config values):

    Code:
    initComponent: function() {
        Ext.apply(this, {
            padding: this.border ? '10px' : '5px',
            bodyBorder: false
        });
        this.callParent();
    }
    Quote Originally Posted by Igor.Szyporyn View Post
    Q: Does a component have all its events accessible like this? Would I also be able to access a added method and expect that code to be executed as the component is added?

    Q: I highly assume that these methods are treated as a single occurrence?

    Q: Is it good or bad practice to use methods such as these?
    No, not all component events are accessible like this - these methods are actually separate from the events of the same name. You can see in Ext.util.Renderable (line 455) how the afterRender method is called:
    Code:
    me.afterRender(); // this can cause a layout
    if (me.hasListeners.afterrender) {
        me.fireEvent('afterrender', me);
    }
    As components are only rendered once, the method will only be called once. I would say it's good practice to take advantage of these methods (in most circumstances) as they have several benefits. First, keeping the method outside the event-firing system saves some overhead in terms of iterating through event listeners - especially since (as you can see from the code) if your component doesn't have any other afterrender listeners, the event won't be fired at all, improving performance. Second, using the inherited methods allows finer control of when your code is executed. Any "afterrender" event listeners will always be called after execution of the afterRender method (as you can again see from the code), but in some cases you may want to inject something before the parent afterRender logic, in which case you could do something like:

    Code:
    afterRender: function() {
        this.setSomeValue(value);
        this.callParent();
    }
    Quote Originally Posted by Igor.Szyporyn View Post
    Q: As you can see I do not call .callParent(arguments) - is this wrong? I mean it can't hurt I guess to send empty arguments in, but I do not see why I should as I have yet to see any component I have extended send along arguments to initComponent.
    That should be fine, I never pass any arguments to callParent() in initComponent either. The only reason it would matter is if Sencha changes the initComponent method in a future version so that it expects an argument, but I think this is quite unlikely (and would probably break other parts of your initComponent code anyway).

    Quote Originally Posted by Igor.Szyporyn View Post
    Q: What is the "correct" way to initialize the config object (as to get automatic getters and setters etc..)
    Using the initConfig method is the correct way to do this. Traditionally, ExtJS does not use initConfig (in contrast with Sencha Touch, which does) but you're welcome to use it in your own components and extensions. Rather than relying on the initialConfig value (which I don't think is documented as part of the public API), this is a case where I would use the constructor over initComponent, as it has easy access to the config object as an argument. I'd also be wary of passing the entire config object to initConfig, as that may interfere with other methods of the same name defined by parent classes. Here's an example of how I'd do it (warning, untested):

    Code:
    constructor: function(config) {
        this.initConfig(
            // initialize only the custom config properties myConfig and otherConfig
            Ext.copyTo({}, config, ['myConfig', 'otherConfig'])
        );
    
        this.callParent(arguments);
    },
    
    initComponent: function() {
        Ext.apply(this, {
            // custom values to override
        });
    
        this.callParent();
    
        // initialize other stuff
        this.addEvents('customevent');
    }

  3. #2
    Sencha User
    Join Date
    Feb 2012
    Location
    Copenhagen
    Posts
    32
    Answers
    1
    Vote Rating
    0
    Igor.Szyporyn is on a distinguished road

      0  

    Default


    Damn, this forum is kind of dead - not much answering going on - so therefore...

    BUMP!

    (Guess I should start answering those of the threads where I can then...)

  4. #3
    Ext JS Premium Member burnnat's Avatar
    Join Date
    Jun 2011
    Posts
    416
    Answers
    42
    Vote Rating
    61
    burnnat is a jewel in the rough burnnat is a jewel in the rough burnnat is a jewel in the rough burnnat is a jewel in the rough

      2  

    Default


    Quote Originally Posted by Igor.Szyporyn View Post
    Q: Is it same same if you use constructor or initComponent - as long as you do not use both at the same time?

    Q: Which is the "correct" way - constructor or initComponent? Or is that maybe dependent on your extension (assume a component here ofc)
    Theoretically either will work, but I almost always override initComponent rather than the constructor, since the config values are available on the component at that point so it's easy to reference and/or override them. For instance, something like this would work in initComponent, but not in a constructor (this.border would be undefined, and Ext.apply(this) would be overwritten by the config values):

    Code:
    initComponent: function() {
        Ext.apply(this, {
            padding: this.border ? '10px' : '5px',
            bodyBorder: false
        });
        this.callParent();
    }
    Quote Originally Posted by Igor.Szyporyn View Post
    Q: Does a component have all its events accessible like this? Would I also be able to access a added method and expect that code to be executed as the component is added?

    Q: I highly assume that these methods are treated as a single occurrence?

    Q: Is it good or bad practice to use methods such as these?
    No, not all component events are accessible like this - these methods are actually separate from the events of the same name. You can see in Ext.util.Renderable (line 455) how the afterRender method is called:
    Code:
    me.afterRender(); // this can cause a layout
    if (me.hasListeners.afterrender) {
        me.fireEvent('afterrender', me);
    }
    As components are only rendered once, the method will only be called once. I would say it's good practice to take advantage of these methods (in most circumstances) as they have several benefits. First, keeping the method outside the event-firing system saves some overhead in terms of iterating through event listeners - especially since (as you can see from the code) if your component doesn't have any other afterrender listeners, the event won't be fired at all, improving performance. Second, using the inherited methods allows finer control of when your code is executed. Any "afterrender" event listeners will always be called after execution of the afterRender method (as you can again see from the code), but in some cases you may want to inject something before the parent afterRender logic, in which case you could do something like:

    Code:
    afterRender: function() {
        this.setSomeValue(value);
        this.callParent();
    }
    Quote Originally Posted by Igor.Szyporyn View Post
    Q: As you can see I do not call .callParent(arguments) - is this wrong? I mean it can't hurt I guess to send empty arguments in, but I do not see why I should as I have yet to see any component I have extended send along arguments to initComponent.
    That should be fine, I never pass any arguments to callParent() in initComponent either. The only reason it would matter is if Sencha changes the initComponent method in a future version so that it expects an argument, but I think this is quite unlikely (and would probably break other parts of your initComponent code anyway).

    Quote Originally Posted by Igor.Szyporyn View Post
    Q: What is the "correct" way to initialize the config object (as to get automatic getters and setters etc..)
    Using the initConfig method is the correct way to do this. Traditionally, ExtJS does not use initConfig (in contrast with Sencha Touch, which does) but you're welcome to use it in your own components and extensions. Rather than relying on the initialConfig value (which I don't think is documented as part of the public API), this is a case where I would use the constructor over initComponent, as it has easy access to the config object as an argument. I'd also be wary of passing the entire config object to initConfig, as that may interfere with other methods of the same name defined by parent classes. Here's an example of how I'd do it (warning, untested):

    Code:
    constructor: function(config) {
        this.initConfig(
            // initialize only the custom config properties myConfig and otherConfig
            Ext.copyTo({}, config, ['myConfig', 'otherConfig'])
        );
    
        this.callParent(arguments);
    },
    
    initComponent: function() {
        Ext.apply(this, {
            // custom values to override
        });
    
        this.callParent();
    
        // initialize other stuff
        this.addEvents('customevent');
    }

  5. #4
    Sencha User
    Join Date
    Feb 2012
    Location
    Copenhagen
    Posts
    32
    Answers
    1
    Vote Rating
    0
    Igor.Szyporyn is on a distinguished road

      0  

    Default


    Awesome reply, I thank you!

    One small point

    As components are only rendered once
    If you move the component from one component to another, would it not render again? (for whatever reasons you would have to do this - could be to wrap a field component in a new fieldcontainer in a plugin maybe)

    Asking because the example I read up on, was one where a component would have more DOM nodes added to a textarea to present how many characters used etc...

    As I understand it - I would get those DOM nodes added over and over if I moved this component to another component - but I could be wrong and the actual rendering event would not fire.

  6. #5
    Ext JS Premium Member burnnat's Avatar
    Join Date
    Jun 2011
    Posts
    416
    Answers
    42
    Vote Rating
    61
    burnnat is a jewel in the rough burnnat is a jewel in the rough burnnat is a jewel in the rough burnnat is a jewel in the rough

      0  

    Default


    A component is only rendered once, the first time it is displayed. When you move a component between containers, the DOM nodes move with it - it doesn't get rerendered. Here's an example fiddle that switches a button between two parent panels. The number of times rendered is displayed in the button text, but you can see it never goes past 1, no matter how many times you click:


  7. #6
    Sencha User
    Join Date
    Feb 2012
    Location
    Copenhagen
    Posts
    32
    Answers
    1
    Vote Rating
    0
    Igor.Szyporyn is on a distinguished road

      0  

    Default


    Thanks, example and all :-)

Thread Participants: 1