Monday, July 8, 2013

Managing Events with Ext JS 4.X


One of the challenges with creating a large single page application with Ext JS 4.X is Event Management. Each click event of the view needs to be (or usually is) wired up in the controller class method. If your controller manages several views, this can lead to a lot of event wiring.
With the Ext JS 4.x framework, there are several ways to wire up your events.  The two that I see the most of are:
1  
1  1)  In the controllers init function, a call to the this.control({}) method is used with the component’s selector to wire up its event to the event handler.

'containerAlias > container button[name=search]': {
     click: this.onCustomerSearch
},
'containerAlias2 container[name=controls] button[name=someaction]': {
     click: this.onSomeAction
},
'containerAlias > container button[name=save]': {
     click: this.onSave
},
'someAliasName button[action=close]': {
      click: this.onClose
},
'SomeAliasName button[name=cancelMe]': {
      click: this.onCancel
},
... (continues…)

The biggest issue I’ve have with using this pattern is that this method call get very, very, very long.  As the number of components in a view or views increase, this method call gets longer and longer.  Also, if the view structure changes, you usually have to come back to change the selectors. This can be time consuming, depending on how many components and events you have.

See the Sencha docs for more information on control method in the Controller class:





2    2)   Another way is to query the container in afterrender event handler and to get each component wired up.

OnContainerRender: function (container) {
        Var searchBtn = container.down('button'),
            addBtn = searchBtn.next(),
            saveBtn = addBtn.next(),
            editBtn = saveBtn.next(),
            isActive = container.down('checkbox'),
     grid = container.down('grid');

        searchBtn.on('click', this.onSearch, this);
        addBtn.on('click', this.onAdd, this);
        saveBtn.on('click', this.onSave, this);
        editBtn.on('click', this.onEdit, this);
        isActive.on('change',this.onIsActiveChange, this);
        grid.on('select', this.onGridSelect, this);

       
},

Again; if the container structure changes, you may have to change the components selector in the up and down methods.  For example if the you added another button before the search button, you would have to change the container.down('button'), to container.down('button').next();.

           See the Sencha docs for more information on up and down method of the Element class and the 
           afterrender event:





Lately I’ve been working with the idea of just having the view expose the events you want to wire up in the controller. This pattern cuts down on the amount of code in the controller and it makes managing of view changes easier.

In the view, override the initComponent method and expose the events with the addEvent method

Step 1:

initComponent: function () {
        this.addEvents({
            save: true,
            close: true,
            select: true,
           
        });
        this.items = this.createItems();
        this.callParent(arguments);
 },


See the Sencha docs for more information on the initComponent and addEvents methods

Step 2:

In the view definition, wire up the components events in the listeners object and have the handler fire the views corresponding event.

//me is a variable to the view (var me = this;)
{
  text: 'Save',
    listeners: {
      click: function (btn, e) {
        me.fireEvent('save', me); //calls the view level event    
      }
  }
},
... Grid definition
listeners: {
    select: function (grid, record, index, e) {
              me.fireEvent('select', me, record, index); //calls the view level event    
    }
}


Notice that you can tailor the arguments that are handle by the view event listener. You can add or cut down the number of arguments needed

See the Sencha docs for more information on the listeners object http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.util.Observable-cfg-listeners

Step 3:
In the controller, wire up the events on the view.
This.control({
     'AliasNameForView’: {
             save: this.onSave,
             close: this.onClose,
             select: this.onQQSelect
      }
});

See the Sencha docs for more information on control method in the Controller class:


The benefits with this pattern are as follows:

1       1) Instead of having to wire up each component separately outside the view, it allows for the isolation of the events to the view itself.

2    2)  The amount of code in the controller to wire up the events is cut down.

3    3) If the structure of the view changes, the code in the controller to wire the event does not have to change.  This allows for better code management.


As we start creating more and more “Single Page Applications” (SPA) web applications and move more business login to the client site, we have to work on better JavaScript code management.  These applications will get very large and we all know that applications change throughout their existence. More we can do to manage the code better will benefit us in the long run.

No comments:

Post a Comment