Creating an Application

Exclusive offer: get 50% off this eBook here
Sencha MVC Architecture

Sencha MVC Architecture — Save 50%

A practical guide for designers and developers to create scalable enterprise-class web applications in ExtJS and Sencha Touch using the Sencha MVC architecture with this book and ebook.

$9.99    $5.00
by Ajit Kumar | December 2012 | Open Source

In this article by Ajit Kumar, author of Sencha MVC Architecture, we will take a step-by-step approach to create a functional application in ExtJS using the MVC architecture and the framework classes related to it. For the sake of completeness and illustration of the concepts, we will be taking up an application requirement and implementing it in ExtJS.

As a requirement, we will be creating an application, which would:

  • Show the list of departments and the users

  • Show the list of users for a selected department

  • Allow the user to edit user information

  • Refresh the users list to get all the users of all the departments

(For more resources related to this topic, see here.)

ExtJS-based application

In ExtJS, we will be dealing with the following classes:

  • Ext.app.Application: This is the application class

  • Ext.app.Controller: This class provides the controller functionality

  • Ext.container.Container, Ext.Component: This class and its sub-classes are used for providing views

  • Ext.data.Model: This class helps us represent a model which the Ext.data.Store class can understand

  • Ext.data.Store: This class contains a collection of Ext.data.Model type objects and is used on the components to show a list of records

Folder structure

In Sencha MVC architecture, folder structure is very important as the underlying class loading uses the pre-defined rules, related to the folder structure, to load the classes automatically for us, on demand.

Create a folder named extjsapp under WebContent in the SenchaArchitectureBook project and add the following files and directories:

  • app: This is the main application directory. This will have the model, view, controller, and store directories:

    • model

    • User.js

    • Department.js

    • store

    • Users.js

    • Departments.js

    • view

    • user\List.js

    • user\Edit.js

    • department\List.js

    • Viewport.js

    • controller

    • Users.js

    • Departments.js

  • data: This contains the JSON datafiles

  • extjs-4.1.0-rc1: This contains the ExtJS framework

  • app.js: This contains the entry point code for the application

  • index.html: This is the HTML for the application

Once created, the folder structure should look like the following screenshot:

Model

Let us define the different models for our application. We will have the following models:

  • User

  • Department

User

Save the following code inside the app\model\User.js file:

Ext.define('AM.model.User', { extend: 'Ext.data.Model', fields: ['id', 'name', 'email','department'], });

The code that we just used defines a User model, which represents a user in the application. AM.model in the class name is important as it is used by the loader to identify the file, which contains the class definition and loads the same. AM is the name of the application, which acts as a namespace. This has been explained, in detail, in the later part of this article.

Department

Save the following code inside the app\model\User.js file:

Ext.define('AM.model.Department', { extend: 'Ext.data.Model', fields: ['code', 'name', 'location'] });

The code that we just used defines a Department model, which represents a department in the application.

 

Sencha MVC Architecture A practical guide for designers and developers to create scalable enterprise-class web applications in ExtJS and Sencha Touch using the Sencha MVC architecture with this book and ebook.
Published: November 2012
eBook Price: $9.99
Book Price: $19.99
See more
Select your format and quantity:

Store

Similar to the models, now let us de fine the stores. In the application, we will have the following stores:

  • Users

  • Departments

Users

Save the following code inside the app\store\Users.js file:

Ext.define('AM.store.Users', { extend: 'Ext.data.Store', model: 'AM.model.User', autoLoad: true, //loads data as soon as the store is initialized proxy: { type: 'ajax', api: { read: 'data/users.json' }, reader: { type: 'json', root: 'users', successProperty: 'success' } }, filterUsersByDepartment: function(deptCode) { this.clearFilter(); this.filter([{ property: 'department', value: deptCode }]); }, refresh: function() { this.clearFilter(); } });

The code that we just used defines a store, which keeps a collection of User models, indicated by the model property. The proxy property contains the information about the AJAX proxy that the store will use to call the specified read URL data/user.json to load the users.Reader is configured based on the users.json file where the root must be set to the config in the users.json file, which contains the user records, which is users.

The autoLoad: true property will tell the framework to load the data into the store as soon as the store is instantiated.

The filterUsersByDepartment method is a public method, which filters the store using the specified department code. This method is called as part of the handling of the selection of a specific department from the Departments List view.

The refresh method is a public method, which clears all the filters applied on the store data and shows all the records in the store. This method is called as part of the handling of the Refresh button click on the Users List view.

Departments

Save the following code inside the app\store\Departments.js file:

Ext.define('AM.store.Departments', { extend: 'Ext.data.Store', model: 'AM.model.Department', autoLoad: true, proxy: { type: 'ajax', api: { read: 'data/departments.json' }, reader: { type: 'json', root: 'departments', successProperty: 'success' } } });

The code that we just used defines store, which would contain the departments data. Every entry in it will be a Department model.

View

The application will have the following views:

  • User List

  • Edit User

  • Department List

User List

Save the following code inside the app\view\user\List.js file:

Ext.define('AM.view.user.List' ,{ extend: 'Ext.grid.Panel', alias : 'widget.userlist', title : 'All Users', store: 'Users', columns: [ {header: 'Name', dataIndex: 'name', flex: 1}, {header: 'Email', dataIndex: 'email', flex: 1} ], tools:[{ type:'refresh', tooltip: 'Refresh', handler: function(){ var pnl = this.up('userlist'); pnl.getStore().refresh(); pnl.setTitle('All Users'); } }], filterUsersByDepartment: function(deptCode) { this.getStore().filterUsersByDepartment(deptCode); } });

The code that we just used defines the User List view, which extends a grid panel. The Users store is associated with it. The grid will show two columns Name and Email, and has a toolbar with the Refresh button. Since, the refresh logic is private to the User List view, the handler is registered in the view class where it is refreshes the store and sets the title correctly.

The filterUsersByDepartment method is a public method, which filters the store using the specified department code. This method is called as part of the handling of the selection of a specific department from the Departments List view. This relies on the store's filterUsersByDepartment entity to accomplish the task.

userlist has been mentioned as an alias, which can be used as xtype for the User List view.

User Edit

Save the following code inside the app\view\user\Edit.js file:

Ext.define('AM.view.user.Edit', { extend: 'Ext.window.Window', alias : 'widget.useredit', requires: ['Ext.form.Panel'], title : 'Edit User', layout: 'fit', autoShow: true, height: 120, width: 280, initComponent: function() { this.items = [ { xtype: 'form', padding: '5 5 0 5', border: false, style: 'background-color: #fff;', items: [ { xtype: 'textfield', name : 'name', fieldLabel: 'Name' }, { xtype: 'textfield', name : 'email', fieldLabel: 'Email' } ] } ]; this.buttons = [ { text: 'Save', action: 'save' }, { text: 'Cancel', action: 'cancel' } ]; this.callParent(arguments); } });

The code that we just used defines the Edit User view. This extends the Window and has a form panel, which contains two text fields and two buttons.

The name property on the text fields has been specified and their value must match with the field name on the User model. This will be helpful in loading the data from the model into the form.

useredit has been mentioned as an alias, which can be used as xtype for the Edit User view.

Department List

Save the following code inside the app\view\department\List.js file:

Ext.define('AM.view.department.List' ,{ extend: 'Ext.grid.Panel', alias : 'widget.departmentlist', title : 'Departments', store: 'Departments', columns: [ {header: 'Name', dataIndex: 'name', flex: 1}, {header: 'Location', dataIndex: 'location', flex: 1} ] });

In the code we just used, we defined the Department List view, which extends a grid panel and uses the Departments store. It has two columns, Name and Location. departmentlist has been mentioned as an alias, which can be used as xtype for the Department List view.

Viewport

Save the following code inside the app\view\Viewport.js file:

Ext.define('AM.view.Viewport', { extend: 'Ext.container.Viewport', requires: ['AM.view.department.List', 'AM.view.user.List'], layout: 'border', config: { items: [{ region: 'west', width: 200, xtype: 'departmentlist' }, { region: 'center', xtype: 'userlist' }] } });

Controller

In the application, we will have the following controllers:

  • Users

  • Departments

Users

Save the following code inside the app\controller\Users.js file:

Ext.define('AM.controller.Users', { extend: 'Ext.app.Controller', config: { stores: ['Users'], models: ['User'], views: ['user.Edit', 'user.List'], refs: [{ ref: 'usersList', selector: 'userlist' }] }, init: function(app) { this.control({ 'userlist dataview': { itemdblclick: this.editUser }, 'useredit button[action=save]': { click: this.updateUser }, 'useredit button[action=cancel]': { click: this.cancelEditUser } }); app.on('departmentselected', function(app, model) { this.getUsersStore().filterUsersByDepartment(model. get('code')); this.getUsersList().setTitle(model.get('name') + ' Users'); }, this); }, editUser: function(grid, record) { var edit = Ext.create('AM.view.user.Edit').show(); edit.down('form').loadRecord(record); }, updateUser: function(button) { var win = button.up('window'), form = win.down('form'), record = form.getRecord(), values = form.getValues(); record.set(values); win.close(); }, cancelEditUser: function(button) { var win = button.up('window'); win.close(); } });

In the code that we just used, we defined the Users controller, which manages the userlist and edituser views. It also uses the Users store and the User model. All these are listed in a controller using the views, stores, and models properties.

The init method in a controller class is called by the framework to initialize the controller, even before the application is launched. The typical task that we do here is registering the handlers for the different view elements. This is done by calling the control method of the controller, where we specify the xtype-based selectors to identify the view component (for example, useredit button[action=save] identifies the Save button on the Edit User window) and register their event handlers.

The controller also handles the departmentselected event in the application, which is fired by the Departments controller when a particular department is selected. Let us see what the Departments controller looks like.

Departments

Save the following code inside the app\controller\Departments.js file:

Ext.define('AM.controller.Departments', { extend: 'Ext.app.Controller', config: { stores: ['Departments'], models: ['Department'], views: ['department.List'] }, init: function() { this.control({ 'departmentlist': { itemclick: this.showDepartmentUser } }); }, showDepartmentUser: function(grid, model, itemEl, idx, e, eOpts) { var app = this.application; app.fireEvent('departmentselected', app, model); } });

The code that we just used defines the Departments controller, which manages the department-related view, model, and the store. It fires the departmentselected event on the application when a department is selected.

Application

Save the following code inside the app.js file:

Ext.application({ name: 'AM', //application name that becomes the namespace // automatically create an instance of AM.view.Viewport autoCreateViewport: true, controllers: [ 'Users', 'Departments' ] });

In the code that we just used, we are initializing the application . The name:'AM' property is a very important property. It creates an automatic namespace for our application. Due to this, we defined all the classes starting with AM, for example, AM.model.User. Once specified, if the framework comes across with any class name starting with AM, it will look for that class in the app folder. For example, when it encounters AM.model.User, it will look for the User.js file inside the app\model folder. Similarly, for AM.view.user.List it will look for the List.js file inside the app\view\user folder.

The autoCreateViewport:true property will tell the framework to automatically look for the Viewport.js file inside the app\view folder and create the viewport using it.

An application is a collection of controllers, which internally manage one or more views to accomplish the overall requirement. All the controllers, which constitute the application, need to be specified as part of the controllers property. A fully qualified name, such as AM.controller.Users, is not required as the framework will automatically look for the Users controller inside the app\controller folder.

index.html

Save the following code inside the index.html file:

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title id="page-title">Account Manager</title> <link rel="stylesheet" type="text/css" href="extjs-4.1.0-rc1/ resources/css/ext-all.css"> <script type="text/javascript" src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="extjs-4.1.0-rc1/ext-debug. js"></script> <script type="text/javascript" src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="app.js"></script> </head> <body> </body> </html>

Publish the application to Apache Tomcat, Start the server, and access http://<host>:<port>/

SenchaArchitectureBook/extjsapp/index.html in the browser. You shall see the following screen:

Selecting a particular department from the Departments list shows the users from the selected department, as shown in the following screenshot:

Double-click on the user record. This will bring up the Edit User view with the values populated from the selected user, as shown in the following screenshot:

Make some change to the user information, say, Name, and click on Save. We shall see the updated information in the users list, as shown in the following screenshot:

Click on the Refresh icon on the users list. This will reload all the users in the users list.

Summary

In this article we took a sample application and learned how to model it as per the MVC architecture and map the different building blocks to the classes provided by ExtJS. The application involved how to identify the views, models, and controllers in an application, how to make use of multiple controllers within an application and pass the data and the control between them to achieve the overall application behavior. We also looked at some of the rules related to class naming conventions, folder structure, and so on, which is required to get the application up and running.

Resources for Article :


Further resources on this subject:


Sencha MVC Architecture A practical guide for designers and developers to create scalable enterprise-class web applications in ExtJS and Sencha Touch using the Sencha MVC architecture with this book and ebook.
Published: November 2012
eBook Price: $9.99
Book Price: $19.99
See more
Select your format and quantity:

About the Author :


Ajit Kumar

Ajit Kumar started his IT career with Honeywell, Bangalore in the field of embedded systems and moved on to enterprise business applications (such as ERP) in his 13 years' career. From day one, he has been a staunch supporter and promoter of open source and believes strongly that open source is the way for a liberal, diversified, and democratic setup, such as India. He dreams, and continuously strives to ensure, that architecture, frameworks, and tools must facilitate software development at the speed of thought.

Ajit holds a Bachelor's degree in Computer Science and Engineering from the Bihar Institute of Technology, Sindri. He co-founded Walking Tree, which is based out of Hyderabad, India where he plays the role of CTO and works on fulfilling his vision.

Prior to writing this book, he worked on the following titles by Packt Publishing:

  • ADempiere 3.6 Cookbook
  • Sencha Touch Cookbook
  • Sencha MVC Architecture

Books From Packt


Sencha Touch Cookbook
Sencha Touch Cookbook

Learning Ext JS 4
Learning Ext JS 4

Sencha Touch Hotshot
Sencha Touch Hotshot

Sencha Touch Mobile JavaScript Framework
Sencha Touch Mobile JavaScript Framework

Ext JS 4 Web Application Development Cookbook
Ext JS 4 Web Application Development Cookbook

ASP.NET MVC 2 Cookbook
ASP.NET MVC 2 Cookbook

ASP.NET MVC 1.0 Quickly
ASP.NET MVC 1.0 Quickly

Catalyst 5.8: the Perl MVC Framework
Catalyst 5.8: the Perl MVC Framework


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software