Skip to main content

ExtJS - View Controller Event Listening

Right now, you fall into one of two groups: those that have Ext 5 and those that do not. Well, I hope you all get into the first group and get to experience the awesome that is Ext 5. I’m super excited about Ext 5 and all the new features and docs it has. Today I want to talk about one of the new features which is to the MVC implementation.
When Ext 4 was released, among one of the major updates to the long standing framework was an MVC implementation. This implementation worked quite well but some were left wanting more. One issue I heard a lot was confusion on the controller, in fact I saw countless people making a single controller per view which in the Ext 4 MVC implementation wasn’t really how it was meant to work. The controllers were really global controllers that can handle any number of different views and their instances; I usually had one controller per feature. I will admit, I deployed this MVC implementation quite successfully and enjoyed developing Ext 4 applications (a huge improvement over Ext 3 and older trust me). But some people still wanted the 1:1 relationship of view to controller and Ext 5 aims to solve this with it’s view controller. Today I want to show an example of using a view controller and how to listen to events on the associated view.
It’s important to note, before we get started, that a view definition can have a view controller definition. That means when the view instance is created, it also instantiates a view controller instance and when the view instance is destroyed so is the view controller instance, they are coupled together through the view lifecycle. So if you have 4 instances of the same view, you will have 4 instances of the view controller.
Let’s begin!
First we need to generate an application using Sencha Cmd 5:
1
sencha generate app -ext MyApp /path/to/MyApp
This will create the default app which is basically a border layout with a west region and a tabpanel as a center region. Let’s make the west region a tree panel showing a file system. First lets create the /path/to/MyApp/view/FileTree.js file with this source:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Ext.define('MyApp.view.FileTree', {
    extend : 'Ext.tree.Panel',
    xtype  : 'myapp-filetree',
    requires : [
        'Ext.toolbar.Toolbar'
    ],
    store : {
        root : {
            text     : '/',
            expanded : true,
            children : [
                {
                    text : 'app.js',
                    leaf : true
                },
                {
                    text : 'index.html',
                    leaf : true
                }
            ]
        }
    },
    dockedItems : [
        {
            xtype : 'toolbar',
            dock  : 'top',
            items : [
                {
                    text : 'Delete'
                }
            ]
        }
    ]
});
We need to use that so we need to edit /path/to/MyApp/view/Main.js to look like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Ext.define('MyApp.view.Main', {
    extend   : 'Ext.container.Container',
    requires : [
        'Ext.tab.Panel',
        'Ext.layout.container.Border',
        'MyApp.view.FileTree'
    ],
    xtype : 'app-main',
    layout : {
        type : 'border'
    },
    items : [
        {
            region : 'west',
            xtype  : 'myapp-filetree',
            title  : 'west',
            width  : 150
        },
        {
            region : 'center',
            xtype  : 'tabpanel',
            items  : [
                {
                    title : 'Center Tab 1'
                }
            ]
        }
    ]
});
Load this up in the browser and you will now see the west region has a file tree panel and if you have a keen eye you will also notice a Delete button but if you click it, it won’t do anything because we aren’t handling the click event. For this, we are going to add a click listener and create a view controller to handle the click listener. In/path/to/MyApp/view/FileTree.js file, find the Delete button config object (should just have the text config currently) and change it to have the listeners config:
1
2
3
4
5
6
{
    text      : 'Delete',
    listeners : {
        click  : 'onDelete'
    }
}
Notice the click listener is a string, this will map to the view controller automatically. Now we need to create the view controller at/path/to/MyApp/view/FileTreeController.js with this source:
1
2
3
4
5
6
7
8
9
10
11
12
Ext.define('MyApp.view.FileTreeController', {
    extend : 'Ext.app.ViewController',
    alias  : 'controller.myapp-filetreecontroller',
    requires : [
        'Ext.window.MessageBox'
    ],
    onDelete : function(button) {
        Ext.Msg.alert('Delete Clicked', 'You clicked on the Delete button!');
    }
});
Now that we created MyApp.view.FileTreeController we need to add that class to the requires array of MyApp.view.FileTree:
1
2
3
4
5
6
requires : [
    'Ext.toolbar.Toolbar',
    'MyApp.view.FileTreeController' //<-- added="" array="" code="" controller="" requires="" the="" to="" view="">
],
controller : 'myapp-filetreecontroller', //<-- alias="" code="" controller="" instantiates="" via="">
So now load the app in the browser again and click that Delete button in the tree panel and you should then see the alert. Remember when we added the listener to the Delete button and we defined the click listener to the string? That string should match the method name in the view controller.
What if you didn’t want to have to add the listeners config to the button, the view controller should automatically listen to the click event without the view defining the listener. It’s quite easy and if you are used to Ext 4 global controllers this won’t be too unfamiliar. First, in /path/to/MyApp/view/FileTree.js we need to find that Delete button config that has the listeners config and remove the listeners so the button config looks like this again:
1
2
3
{
    text : 'Delete'
}
Now we need to edit /path/to/MyApp/view/FileTreeController.js to listen to the button’s click event so we can get back to seeing that alert message. For this we need to use the control config, here is the entire source for the FileTreeController.jsfile to show where the config object can go:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Ext.define('MyApp.view.FileTreeController', {
    extend : 'Ext.app.ViewController',
    alias  : 'controller.myapp-filetreecontroller',
    requires : [
        'Ext.window.MessageBox'
    ],
    config : {                             // 1
        control : {                        // 2
            'button' : {                   // 3
                click : 'onDelete'         // 4
            }
        }
    },
    onDelete : function(button) {
        Ext.Msg.alert('Delete Clicked', 'You clicked on the Delete button!');
    }
});
I’ve added four comments so I can easily describe what’s going on. The 1 commented line is where we define the config property, note that this is in the first level of that object. commented line is the control config which is going to listen to events, this should be similar to using this.control in an Ext 4 controller. In the 3 commented line, we have‘button’ as a string, the reason we have it as a string is to signify that this is actually anExt.ComponentQuery selector. Technically you could remove the single quotes but I always keep them to show it’s a selector as other selectors may contain other characters that could be invalid like spaces. The 4 commented line is the click listener like we had before and it also is set to be a string which will map to the onDelete method on the class.
Run the updates in the browser and if you have done everything correctly you should once again see the alert. So now you can decide whether you want to define the listeners for any descendants in the view itself using the listeners config or in the view controller.
A caveat with using the listeners method of listening to the component events is that if you define listeners directly on the class (MyApp.view.FileTree for this example) is that it won’t get listened to automatically in the view controller like it does for descendant components. What I mean is if you tried to do something like this:
1
2
3
4
5
6
7
8
9
10
Ext.define('MyApp.view.FileTree', {
    extend : 'Ext.tree.Panel',
    xtype  : 'myapp-filetree',
    // ...
    listeners : {
        itemclick : 'onNodeClick'
    }
});
This will trigger the onNodeClick method you have in the view controller like you may expect. Another way to listen to the itemclick event on MyApp.view.FileTree is to use the control config in the view controller but use the selector ‘#’:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Ext.define('MyApp.view.FileTreeController', {
    extend : 'Ext.app.ViewController',
    alias  : 'controller.myapp-filetreecontroller',
    requires : [
        'Ext.window.MessageBox'
    ],
    config : {
        control : {
            '#'      : {
                itemclick : 'onNodeClick'
            },
            'button' : {
                click : 'onDelete'
            }
        }
    },
    onDelete : function() {
        Ext.Msg.alert('Delete Clicked', 'You clicked on the Delete button!');
    },
    onNodeClick : function(treeview, node) {
        Ext.Msg.alert('Node Clicked', 'You clicked on the node: ' + node.get('text'));
    }
});
Now once you refresh the browser and click on one of the tree nodes, you should then see the alert message saying you clicked on it.

Popular posts from this blog

ExtJS - Grid panel features

What can we do with ExtJS GridPanel? I have to develop a lot of applications in my web app and I see that grid component of ExtJS may fit in. However, I am not aware of what all things I can do with the - off the shelf available framework pieces - available plug-ins in the marketplace and - custom development through my own developers This is a typical question that we hear from the business users who wants to design an application by keeping the framework’s capability in perspective. In this article I have tried to put the list of stuff you can do with grid and hopefully that shall enable you to take advantage of the beauty of ExtJS. Pre-requisites This article assumes that you are familiar with basics of ExtJS What are the available options? In this section I will be taking you through some of the commonly seen usage of ExtJS grid panel. While covering all the capabilities of grid may not be possible, I am sure it will be helpful for the business users who want to

Ext4 Apply Store Filtering

In extjs4.1: There are many way for store filtering . Some of code i give here Filtering by single field: store . filter ( 'eyeColor' , 'Brown' );   Alternatively, if filters are configured with an  id , then existing filters store may be  replaced by new filters having the same  id . Filtering by single field: store . filter ( "email" , /\.com$/ );   Using multiple filters: store . filter ([ { property : "email" , value : /\.com$/ }, { filterFn : function ( item ) { return item . get ( "age" ) > 10 ; }} ]);   Using  Ext.util.Filter  instances instead of config objects (note that we need to specify the root config option in this case): store . filter ([ Ext . create ( ' Ext.util.Filter ' , {   property : "email" , value : /\.com$/ , root : 'data' }),   Ext . create ( ' Ext.util.Filter ' , {   filterFn : function ( item ) {   return item . get ( &

EXT JS 4: EMPTY VALUE IN A COMBOBOX

EXT JS 4: EMPTY VALUE IN A COMBOBOX Often, in an Ext JS combobox, it is difficult to go back to an empty value once you have selected an item, particularly if “forceSelection” is set to true.  Here is my roundup of alternative solutions found from around the web… 1. Override beforeBlur The solution from   http://www.sencha.com/forum/showthread.php?182119-How-To-Re-Empty-ComboBox-when-forceSelection-is-Set-To-TRUE  overrides beforeBlur on the combbox to clear out lastSelection.  Here is a copy of the override from the thread: 1 2 3 4 5 6 7 8 9 10 11 12 13 Ext.create( 'Ext.form.field.ComboBox' , {      ...      allowBlank: true ,      forceSelection: true ,      beforeBlur: function (){          var value = this .getRawValue();          if (value == '' ){              this .lastSelection = [];          }          this .doQueryTask.cancel();         this .assertValue();      } }); Or to apply the o