ExtJs 4 Tree Grid example with column headers, checkboxes and menu options using Java Servlet, JSON and MySQL - Part 2

Click here for previous Chapter
In the previous chapter we have created the index file, our application JavaScript file, the model for the Tree representation and the Tree Store that will get the data from Java Servlet in JSON format using AJAX request and keep them saved. Lets move forward with our application.

Tree panel that will display the Whole world dividing them into continents and various regions - CountryTree.js

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Ext.define('MYTREE.view.CountryTree', {
    extend: 'Ext.tree.Panel',
    alias: 'widget.countryTree',
    store: 'Countries',
    title: 'The whole world in a Tree Panel with Column Headers',
    height: 400,
    width: 800,
    padding: '5 5 5 5',
    useArrows: true,
    multiSelect: true,
    singleExpand: true,
    rootVisible: false,
    dockedItems: [{
        dock: 'bottom',
        items: [{
                    xtype : 'button',
                    text: 'Get all checked nodes',
                    action: 'getCheckedNodes'
                }
        ]
    }],
    columns: [
            {
                //treecolumn xtype tells the Grid which column will show the tree
                xtype: 'treecolumn',
                text: 'Continents -> Regions -> Countries',
                flex: 2,
                sortable: true,
                dataIndex: 'text'
            },
            {
                text: 'Population',
                flex: 1,
                sortable: true,
                dataIndex: 'population',
                align: 'right'
            },
            {
                text: 'Surface Area',
                flex: 1,
                sortable: true,
                dataIndex: 'surfaceArea',
                align: 'right',
            },
            {
                text: 'Life Expectancy',
                flex: 1,
                sortable: true,
                dataIndex: 'lifeExpectancy',
                align: 'right'
            },
            {
                text: 'GNP',
                flex: 1,
                sortable: true,
                dataIndex: 'gnp',
                align: 'right',
            },
            {
                //templatecolumn helps us provide a custom template using tpl property
                xtype: 'templatecolumn',
                text: 'Capital',
                flex: 1,
                sortable: true,
                dataIndex: 'capital',
                tpl: '  {capital}'
            }
            
         ]
});

Next we create the menus so that we can add, edit and delete a country - AddMenu.js and EditMenu.js


ExtJs 4 Tree Grid with checkboxes and menu options using Java Servlet, JSON and MySQL
ExtJs 4 Tree Grid with checkboxes and menu options using Java Servlet, JSON and MySQL
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
38
39
40
41
42
43
44
45
46
47
48
Ext.define('MYTREE.view.AddMenu', {
    extend: 'Ext.menu.Menu',
    alias: 'widget.addMenu',
    width: 120,
 
    initComponent: function() {
        var me = this;
 
        Ext.applyIf(me, {
            items: [
                {
                    xtype: 'menuitem',
                    text: 'Add',
                    iconCls: 'icon-add'
                }
            ]
        });
 
        me.callParent(arguments);
    }
});
 
Ext.define('MYTREE.view.EditMenu', {
    extend: 'Ext.menu.Menu',
    alias: 'widget.editMenu',
    width: 120,
 
    initComponent: function() {
        var me = this;
 
        Ext.applyIf(me, {
            items: [
                {
                    xtype: 'menuitem',
                    text: 'Edit',
                    iconCls: 'icon-edit'
                },
                {
                    xtype: 'menuitem',
                    text: 'Delete',
                    iconCls: 'icon-delete',  
                }
            ]
        });
 
        me.callParent(arguments);
    }
});

Now we need a Window that will display the country information when we click on the edit menu option so that we can make changes - CountryEdit.js


ExtJs 4 Tree Grid with checkboxes and menu options using Java Servlet, JSON and MySQL
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
Ext.define('MYTREE.view.CountryEdit', {
    extend: 'Ext.window.Window',
    alias : 'widget.countryEdit',
    addMode : false,
    title : 'Country Information',
    layout: 'fit',
    //autoShow: true,
 
    initComponent: function() {
        this.items = this.buildItems();
        this.buttons = this.buildButtons();
        this.callParent(arguments);
    },
    buildItems: function(){
        return [
                {
                    xtype: 'form',
                    items: [
                        {
                            xtype: 'textfield',
                            itemId : 'code',
                            name : 'code',
                            allowBlank: false,
                            msgTarget: 'side',
                            fieldLabel: 'Country Code',
                            size: 5,
                            maxLength: 5
                        },  
                        {
                            xtype: 'textfield',
                            name : 'text',
                            allowBlank: false,
                            msgTarget: 'side',
                            fieldLabel: 'Country Name',
                            size: 31,
                            maxLength: 30
                        },
                        {
                            xtype: 'textfield',
                            name : 'capital',
                            allowBlank: false,
                            msgTarget: 'side',
                            fieldLabel: 'Capital',
                            size: 31,
                            maxLength: 30
                        },
                        {
                            xtype: 'numberfield',
                            name : 'population',
                            value: 0,
                            minValue: 0,
                            fieldLabel: 'Population',
                            decimalPrecision:0,
                            step: 1.00
                         },
                         {
                            xtype: 'numberfield',
                            name : 'surfaceArea',
                            value: 0,
                            minValue: 0,
                            fieldLabel: 'Surface Area',
                            decimalPrecision:2,
                            step: 0.01
                         },
                         {
                            xtype: 'numberfield',
                            name : 'lifeExpectancy',
                            value: 0,
                            minValue: 0,
                            fieldLabel: 'Life Expectancy',
                            decimalPrecision:2,
                            step: 0.01,
                            itemId : 'lifeExpectancy'
                         },
                         {
                            xtype: 'numberfield',
                            name : 'gnp',
                            value: 0,
                            minValue: 0,
                            fieldLabel: 'GNP',
                            decimalPrecision:2,
                            step: 0.01,
                            itemId : 'gnp'
                         },
                         {
                             xtype: 'hiddenfield',
                             name : 'parentNodeId',
                             itemId : 'parentNodeId'
                         }
                    ]
                }
            ];
    },
    buildButtons: function(){
        return [
                {
                    text: 'Save',
                    action: 'save'
                },
                {
                    text: 'Cancel',
                    scope: this,
                    handler: this.close
                }];
    }
    
});

Now that we have created all our components its time to create the controller that will bind all these together and provide the functionality we need from this Tree panel - Countries.js

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
Ext.define('MYTREE.controller.Countries', {
            extend : 'Ext.app.Controller',
 
            //define the stores
            stores : ['Countries'],
            //define the models
            models : ['Country'],
            //define the views
            views : ['CountryTree', 'EditMenu', 'AddMenu', 'CountryEdit'],
            refs : [{
                        //reference to the country Tree
                        ref : 'myCountryTree',
                        selector : 'countryTree'
                    }, {
                        //reference to the country window
                        ref : 'myCountryWindow',
                        selector : 'countryEdit'
                    }],
 
            init : function() {
                this.control({
 
                            'viewport' : {
                                render : this.onPanelRendered
                            },
                            //Tree events - click, checkbox change, node expand and right click
                            'countryTree' : {
                                itemclick : this.treeItemClick,
                                checkchange : this.treeCheckChange,
                                itemexpand : this.treeNodeExpand,
                                itemcontextmenu : this.treeRightClick
                            },
                            //get all checked noded button
                            'countryTree button[action=getCheckedNodes]' : {
                                click : this.getAllCheckedNodes
                            },
                            //edit a country
                            'editMenu menuitem[text=Edit]' : {
                                click : this.editCountry
                            },
                            //delete a country
                            'editMenu menuitem[text=Delete]' : {
                                click : this.deleteCountry
                            },
                            //add a country
                            'addMenu menuitem[text=Add]' : {
                                click : this.addCountry
                            },
                            //save country info from the edit window
                            'countryEdit button[action=save]' : {
                                click : this.saveCountry
                            }
                        });
            },
 
            onPanelRendered : function() {
                //just a console log to show when the panel is rendered
                console.log('The panel was rendered');
            },
 
            treeItemClick : function(view, record) {
                //some node in the tree was clicked
                //you have now access to the node record and the tree view
                console.log('Clicked on a Tree Node!\n' + 'Node id: '
                        + record.get('id') + '\n' + 'Node Text: '
                        + record.get('text') + '\n' + 'Parent Node id: '
                        + record.get('parentId') + '\n' + 'Is it a leaf?: '
                        + record.get('leaf') + '\n' + 'No of Children: '
                        + record.childNodes.length);
                //now you have all the information about the node
                //Node id
                //Node Text
                //Parent Node
                //Is the node a leaf?
                //No of child nodes
                //......................
                //go do some real world processing
            },
 
            //event triggred when a node is checked or unchecked
            treeCheckChange : function(node, checked) {
                console.log('Checkbox clicked: Is it checked? ' + checked);
                console.log('Is the node loaded? ' + node.isLoaded());
                //loops thru all child nodes and check or uncheck
                //based on the parent node that was clicked
                node.eachChild(function(childNode) {
                            childNode.set('checked', checked);
                            //keep going
                            this.treeCheckChange(childNode, checked);
                        }, this);
            },
 
            //node expand event
            treeNodeExpand : function(node) {
                console.log('Expanded Node: How many children? '
                        + node.childNodes.length);
            },
 
            //get all nodes that are checked in the Tree panel
            getAllCheckedNodes : function(button) {
                selectedNodes = this.getMyCountryTree().getChecked();
                console.log('List of Selected Nodes:\n');
                Ext.Array.each(selectedNodes, function(record) {
                            console.log('Node:' + record.get('id') + ' Text:'
                                    + record.get('text') + '\n');
                        });
            },
 
            //display the context menu
            treeRightClick : function(view, record, item, index, e) {
                //stop the default action
                e.stopEvent();
                //save the current selected record
                this.application.currentRecord = record;
                //if the node is a region let user add a country
                if (record.get('depth') === 2) {
                    addMenu = Ext.widget('addMenu');
                    addMenu.showAt(e.getXY());
                }
                //if the node is country let the user edit or delete
                if (record.get('depth') === 3) {
                    editMenu = Ext.widget('editMenu');
                    editMenu.showAt(e.getXY());
                }
                return false;
            },
 
            //edit the country
            editCountry : function(item, e) {
                console.log(this.application.currentRecord);
                //get reference to the window for editing
                countryWindow = this.getMyCountryWindow();
                //create the window for editing if it doesn't exist
                if(!countryWindow){
                    countryWindow = Ext.widget('countryEdit');
                }
                //load the record into the form
                countryWindow.down('form').loadRecord(this.application.currentRecord);
                //get the Country code field in the form and protect it
                countryWindow.down('form').getComponent('code').setReadOnly(true);
                //set the parent node id in the hidden field
                countryWindow.down('form').getComponent('parentNodeId')
                        .setValue(this.application.currentRecord.parentNode.get('id'));
                //display the window      
                countryWindow.show();
            },
 
            addCountry : function(item, e) {
                console.log(this.application.currentRecord);
                //get reference to the window for editing
                countryWindow = this.getMyCountryWindow();
                //create the window for editing if it doesn't exist
                if(!countryWindow){
                    countryWindow = Ext.widget('countryEdit');
                }
                //set to Add mode
                countryWindow.addMode = true;
                //load blank record into the form
                blankCountry = new MYTREE.model.Country();
                countryWindow.down('form').loadRecord(blankCountry);
                //get the Country code field in the form and unprotect it
                countryWindow.down('form').getComponent('code').setReadOnly(false);
                //set the current node as parent node id in the hidden field
                countryWindow.down('form').getComponent('parentNodeId')
                        .setValue(this.application.currentRecord.get('id'));      
                countryWindow.down('form').getComponent('lifeExpectancy').setValue(0);
                countryWindow.down('form').getComponent('gnp').setValue(0);
                //display the window
                countryWindow.show();
            },
 
            //delete a country
            deleteCountry : function(item, e) {
                console.log(this.application.currentRecord);
                //set action as delete
                type = 'delete';
                //node is the parent node id
                node = this.application.currentRecord.parentNode.get('id');
                //data is the current node id
                data = this.application.currentRecord.get('id');
                //send the request to the server
                this.sendMyRequest(type, node, data);
            },
 
            //save the country information from the editing window
            saveCountry : function(button) {
                //get access to the window using the button reference
                var win = button.up('window');
                //get access to the form using the window reference
                form = win.down('form');
 
                //check if the form passed all validations
                if (form.getForm().isValid()) {
                    //if there are no errors then send the Add request to server
                    countryWindow = this.getMyCountryWindow();
                    //set the action based on window mode
                    if(countryWindow.addMode){
                        type = 'add';
                    }
                    else{
                        type = 'edit';
                    }
                    //get parent node from the hidden field
                    node = form.getComponent('parentNodeId').getValue();
                    //encode the form values to a JSON object
                    data = Ext.encode(form.getValues());
                    //send the request to server
                    this.sendMyRequest(type, node, data);
                    //close the window
                    win.close();
                }
            },
 
            //sending the add, edit and delete transactions to server
            sendMyRequest: function(type, node, data){
                
                //create an AJAX request
                Ext.Ajax.request({
                    url : 'CountryServlet',
                    params : {
                        action: type,
                        parentNodeId: node,
                        myData: data
                    },
                    scope : this,
                    //method to call when the request is successful
                    success : this.onSaveSuccess,
                    //method to call when the request is a failure
                    failure : this.onSaveFailure
                });
                
            },
            
            onSaveFailure : function(err) {
                //Alert the user about communication error
                Ext.MessageBox.alert('Status', 'Error occured during Item Add');
            },
 
            onSaveSuccess : function(response, opts) {
                //Alert the user about communication error
                if(opts.params.action === 'edit'){
                    Ext.MessageBox.alert('Status', 'Country Updated!');
                }
                if(opts.params.action === 'add'){
                    Ext.MessageBox.alert('Status', 'Country Added!');
                }
                if(opts.params.action === 'delete'){
                    Ext.MessageBox.alert('Status', 'Country Deleted!');
                }
                //get refernce to the node that needs to be reloaded to match data with the server
                refreshNode = this.getCountriesStore().getNodeById(opts.params.parentNodeId);
                //unnecessary but required here due to an ExtJS bug
                refreshNode.removeAll(false);
                //refresh(reload) the node
                this.getCountriesStore().load({
                    node : refreshNode
                });
            }
 
        });

Click here for next Chapter

No comments:

Post a Comment

NO JUNK, Please try to keep this clean and related to the topic at hand.
Comments are for users to ask questions, collaborate or improve on existing.