Ext JS 4: Working with the Grid Component

Exclusive offer: get 50% off this eBook here
Ext JS 4 First Look

Ext JS 4 First Look — Save 50%

A practical guide including examples of the new features in Ext JS 4 and tips to migrate from Ext JS 3 with this book and ebook.

$26.99    $13.50
by Loiane Groner | January 2012 | Java Open Source

In this article by Loiane Groner, author of Ext JS 4 First Look we will cover some new features and enhancements in the Grid Component. Ext JS 4 introduces major changes compared to Ext JS 3. There is a new data package, new charts, and new, updated layouts. The framework was completely rewritten to boost performance.

(For more resources on JavaScript, see here.)

Grid panel

The grid panel is one of the most-used components when developing an application Ext JS 4 provides some great improvements related to this component.

The Ext JS 4 Grid panel renders a different HTML than Ext JS 3 Grid did. Sencha calls this new feature Intelligent Rendering. Ext JS 3 used to create the whole structure, supporting all the features. But, what if someone just wanted to display a simple grid? All the other features not being rendered would just be wasted, because no one was using that structure. Ext JS 4 now renders only the features the grid uses, minimizing and boosting the performance.

Before we examine the grid's new features and enhancements, let's take a look how to implement a simple grid in Ext JS 4:

Ext.create('Ext.grid.Panel', { store: Ext.create('Ext.data.ArrayStore', { fields: [ {name: 'book'}, {name: 'author'} ], data: [['Ext JS 4: First Look','Loiane Groner']] }), columns: [ { text : 'Book', flex : 1, sortable : false, dataIndex: 'book' },{ text : 'Author', width : 100, sortable : true, dataIndex: 'author' }], height: 80, width: 300, title: 'Simple Grid', renderTo: Ext.getBody() });

As you can see in the preceding code, the two main parts of the grid are the store and the columns declarations. Note, as well, names of both store and model fields always have to match with the column's dataIndex (if you want to display the column in the grid).

So far, nothing has changed. The way we used to declare a simple grid in Ext JS 3 is the same way we do for Ext JS 4.

However, there are some changes related to plugins and the new features property. We are going to take a closer look at that in this section.

Let's dive into the changes!

Columns

Ext JS 4 organizes all the column classes into a single package—the Ext.grid.column package.

We will explain how to use each column type with an example. But first, we need to declare a Model and a Store to represent and load the data:

Ext.define('Book', { extend: 'Ext.data.Model', fields: [ {name: 'book'}, {name: 'topic', type: 'string'}, {name: 'version', type: 'string'}, {name: 'released', type: 'boolean'}, {name: 'releasedDate', type: 'date'}, {name: 'value', type: 'number'} ] }); var store = Ext.create('Ext.data.ArrayStore', { model: 'Book', data: [ ['Ext JS 4: First Look','Ext JS','4',false,null,0], ['Learning Ext JS 3.2','Ext JS','3.2',tr ue,'2010/10/01',40.49], ['Ext JS 3.0 Cookbook','Ext JS','3',true,'2009/10/01',44.99], ['Learning Ext JS','Ext JS','2.x',true,'2008/11/01',35.99], ] });

Now, we need to declare a grid:

Ext.create('Ext.grid.Panel', { store: store, width: 550, title: 'Ext JS Books', renderTo: 'grid-example', selModel: Ext.create('Ext.selection.CheckboxModel'), //1 columns: [ Ext.create('Ext.grid.RowNumberer'), //2 { text: 'Book',//3 flex: 1, dataIndex: 'book' },{ text: 'Category', //4 xtype:'templatecolumn', width: 100, tpl: '{topic} {version}' },{ text: 'Already Released?', //5 xtype: 'booleancolumn', width: 100, dataIndex: 'released', trueText: 'Yes', falseText: 'No' },{ text: 'Released Date', //6 xtype:'datecolumn', width: 100, dataIndex: 'releasedDate', format:'m-Y' },{ text: 'Price', //7 xtype:'numbercolumn', width: 80, dataIndex: 'value', renderer: Ext.util.Format.usMoney },{ xtype:'actioncolumn', //8 width:50, items: [{ icon: 'images/edit.png', tooltip: 'Edit', handler: function(grid, rowIndex, colIndex) { var rec = grid.getStore().getAt(rowIndex); Ext.MessageBox.alert('Edit',rec.get('book')); } },{ icon: 'images/delete.gif', tooltip: 'Delete', handler: function(grid, rowIndex, colIndex) { var rec = grid.getStore().getAt(rowIndex); Ext.MessageBox.alert('Delete',rec.get('book')); } }] }] });

The preceding code outputs the following grid:

  • The first column is declared as selModel, which, in this example, is going to render a checkbox, so we can select some rows from the grid. To add this column into a grid, simply declare the selModel (also known as sm in Ext JS 3) as CheckBox selection model, as highlighted in the code (comment 1 in the code).
  • The second column that we declared is the RowNumberer column. This column adds a row number automatically into the grid.
  • In the third column (with text:'Book'), we did not specify a column type; this means the column will display the data itself as a string.
  • In the fourth column, we declared a column with xtype as templatecolumn. This column will display the data from the store, specified by an XTemplate, as declared in the tpl property. In this example, we are saying we want to display the topic (name of the technology) and its version.
  • The fifth column is declared as booleancolumn. This column displays a true or false value. But, if we do not want to display true or false in the grid, we can specify the values that we want to get displayed. In this example, we displayed the value as Yes (for true values) and No (for false values), as we declared in the trueText and falseText.
  • The sixth column we declared as datecolumn, which is used to display dates. We can also declare a date format we want to be displayed. In this example, we want to display only the month and the year. The format follows the same rules for PHP date formats.
  • The seventh column we declared as numbercolumn. This column is used to display numbers, such as a quantitative number, money, and so on. If we want to display the number in a particular format, we can use one of the Ext JS renderers to create a customized one.
  • And the last column we declared is the actioncolumn. In this column, we can display icons that are going to execute an action, such as delete or edit. We declare the icons we want to display in the items property.
    • topic: {name}{rows.length} Book
    • topic: {name}{rows.length} Books

Feature support

In Ext JS 3, when we wanted to add a new functionality to a grid, we used to create a plugin or extend the GridPanel class. There was no default way to do it. Ext JS 4 introduces the Ext.grid.feature.Feature class that contains common methods and properties to create a plugin.

Inside the Ext.grid.feature packages, we will find seven classes: AbstractSummary, Chunking, Feature, Grouping, GroupingSummary, RowBody, and Summary.

A feature is very simple to use—we need to add the feature inside the feature declaration in the grid:

features: [{ groupHeaderTpl: 'Publisher: {name}', ftype: 'groupingsummary' }]

Let's take a look at how to use some of these native grid features.

Ext.grid.feature.Grouping

Grouping rows in Ext JS 4 has changed. Now, Grouping is a feature and can be applied to a grid through the features property.

The following code displays a grid grouped by book topic:

Ext.define('Book', { extend: 'Ext.data.Model', fields: ['name', 'topic'] }); var Books = Ext.create('Ext.data.Store', { model: 'Book', groupField: 'topic', data: [{ name: 'Learning Ext JS', topic: 'Ext JS' },{ name: 'Learning Ext JS 3.2', topic: 'Ext JS' },{ name: 'Ext JS 3.0 Cookbook', topic: 'Ext JS' },{ name: 'Expert PHP 5 Tools', topic: 'PHP' },{ name: 'NetBeans IDE 7 Cookbook', topic: 'Java' },{ name: 'iReport 3.7', topic: 'Java' },{ name: 'Python Multimedia', topic: 'Python' },{ name: 'NHibernate 3.0 Cookbook', topic: '.NET' },{ name: 'ASP.NET MVC 2 Cookbook', topic: '.NET' }] }); Ext.create('Ext.grid.Panel', { renderTo: Ext.getBody(), frame: true, store: Books, width: 350, height: 400, title: 'Books', features: [Ext.create('Ext.grid.feature.Grouping',{ groupHeaderTpl: 'topic: {name} ({rows.length} Book{[values.rows.length > 1 ? "s" : ""]})' })], columns: [{ text: 'Name', flex: 1, dataIndex: 'name' },{ text: 'Topic', flex: 1, dataIndex: 'topic' }] });

In the groupHeaderTpl attribute, we declared a template to be displayed in the grouping row. We are going to display one of the following customized strings, depending on the number of books belonging to the topic:

The string comprises of the topic name ({name}) and the count of the book for the topic ({rows.length}).

In Ext JS 3, we still had to declare a grouping field in the store; but, instead of a Grouping feature, we used to declare GroupingView, as follows:

view: new Ext.grid.GroupingView({ forceFit:true, groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Books" : "Book"]})' })

If we execute the grouping grid, we will get the following output:

 

Ext.grid.feature.GroupingSummary

The GroupingSummary feature also groups rows with a field in common, but it also adds a summary row at the bottom of each group.

Let's change the preceding example to use the GroupingSummary feature:

Ext.create('Ext.grid.Panel', { renderTo: Ext.getBody(), frame: true, store: Books, width: 350, height: 400, title: 'Books', features: [{ groupHeaderTpl: 'Topic: {name}', ftype: 'groupingsummary' }], columns: [{ text: 'Name', flex: 1, dataIndex: 'name', summaryType: 'count', summaryRenderer: function(value){ return Ext.String.format('{0} book{1}', value, value !== 1 ? 's' : ''); } },{ text: 'Topic', flex: 1, dataIndex: 'topic' }] });

We highlighted two pieces in the preceding code. The first line is the feature declaration: in the previous example (Grouping) we created the feature using the Ext.create declaration. But if we do not want to explicitly create the feature every time we declare, we can use the ftype property, which is groupingsummary in this example.

The groupingsummary that we added to the grid's name column is in the second line of highlighted code. We declared a summaryType property and set its value as count. Declaring the summaryType as count means we want to display the number of books in that particular topic/category; it is going to count how many records we have for a particular category in the grid. It is very similar to the count of the PL/SQL language. Other summary types we can declare are: sum, min, max, average (these are self-explanatory).

In this example, we want to customize the text that will be displayed in the summary, so we are going to use the summaryRenderer function. We need to pass a value argument to it, and the value is the count of the name column. Then, we are going to return a customized string that is going to display the count (token {0}) and the string book or books, depending on the count (if it is more than 1 we add s at the end of the string book).

Ext.String.format is a function that allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each token must be unique and must increment in the format {0}, {1}, and so on.

The preceding code will output the following grid:

Ext.grid.feature.Summary

The GroupingSummary feature adds a row at the bottom of each grouping. The Summary feature adds a row at the bottom of the grid to display summary information. The property configuration is very similar to that for GroupingSummary, because both classes are subclasses of AbstractSummary (a class that provides common properties and methods for summary features).

Ext.create('Ext.grid.Panel', { renderTo: Ext.getBody(), frame: true, store: Books, width: 350, height: 300, title: 'Books', features: [{ ftype: 'summary' }], columns: [{ text: 'Name', flex: 1, dataIndex: 'name', summaryType: 'count', summaryRenderer: function(value){ return Ext.String.format('{0} book{1}', value, value !== 1 ? 's' : ''); } },{ text: 'Topic', flex: 1, dataIndex: 'topic' }] });

The only difference from the GroupingSummary feature is the feature declaration itself. The summayType and summaryRenderer properties work in a similar way. The preceding code will output the following grid:

Ext.grid.feature.RowBody

The rowbody feature adds a new tr->td->div in the bottom of the row that we can use to display additional information.

Here is how to use it:

Ext.create('Ext.grid.Panel', { renderTo: Ext.getBody(), frame: true, store: Books, width: 350, height: 300, title: 'Books', features: [{ ftype: 'rowbody', getAdditionalData: function(data, idx, record, orig) { return { rowBody: Ext.String.format( '

->topic: {0}
', data.topic) }; } }, { ftype: 'rowwrap' }], columns: [{ text: 'Name', flex: 1, dataIndex: 'name' }] });

 

In the preceding code, we are not only displaying the name of the book; we are using the rowbody to display the topic of the book as well.

The first step is to declare the rowbody feature. One very important thing to be noted is that rowbody will be initially hidden, unless you override the getAdditionalData method.

If we execute the preceding code, we will get the following output:

Ext JS 4 First Look A practical guide including examples of the new features in Ext JS 4 and tips to migrate from Ext JS 3 with this book and ebook.
Published: January 2012
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

(For more resources on JavaScript, see here.)

Grid plugins

Ext JS 4 also introduces a plugin package with five classes: Editing, CellEditing, RowEditing, HeaderResizing, and DragDrop.

The Editing class is an abstract class that provides common methods and properties for editing a grid. Its subclasses are CellEditing and RowEditing.

Ext.grid.plugin.CellEditing

The CellEditing plugin enables editing in a particular cell of the grid. When you click on the cell (the cell has to be enabled for editing) the editor (field instance or field configuration) will open and we can edit its value.

Before we get to the code for the cell that needs to be edited, we will declare a store:

Ext.define('Contact', { extend: 'Ext.data.Model', fields: ['name', 'email','phone'] }); var Contacts = Ext.create('Ext.data.Store', { model: 'Contact', data: [ {name: 'Loiane', email: 'me@loiane.com', phone: '1234-5678'}, {name: 'Peter', email: 'peter@email.com', phone: '2222-2222'}, {name: 'Ane', email: 'ane@email.com', phone: '3333-3333'}, {name: 'Harry', email: 'harry@email.com', phone: '4444-4444'}, {name: 'Camile', email: 'camile@email.com', phone: '5555-5555'} ] });

Now, let's get to the code for the cell that needs to be edited:

Ext.create('Ext.grid.Panel', { renderTo: Ext.getBody(), frame: true, store: Contacts, width: 350, title: 'Contacts', selType: 'cellmodel', columns: [{ text: 'Name', flex: 1, dataIndex: 'name' },{ text: 'Email', flex: 1, dataIndex: 'email', editor: { xtype:'textfield', allowBlank:false } },{ text: 'Phone', flex: 1, dataIndex: 'phone', editor: { xtype:'textfield', allowBlank:false } }], plugins: [ Ext.create('Ext.grid.plugin.CellEditing', { clicksToEdit: 1 }) ] });

In the preceding code, we have to pay attention to a few things: the first one is the plugins declaration. We declared a CellEditing plugin and we also set the clicksToEdit property to 1, which means the users have to click on the specific cell to be able to edit it. Declaring only the plugin is not enough in order to make the cell editable. We also have to add the editor option to the cell.

We declared, inside the columns property, an editor property. The editor property is an Ext.form.field.Field object, which means you can use its properties to configure as if it is a text field, a combobox, a checkbox, or any other component from the field package. The columns are editable only after adding the editor property. In the preceding example, we added the editor property to the Email and Phone columns, so these columns become editable when we click on them. We did not add the editor property for the Name column, thus it will not be editable when we click on it.

Another highlighted line is the selType property. We set cellModel as the selection model (known as the sm property in Ext JS 3), which means that, when we click on a row of the grid, the cell we clicked on will be selected. The default one is rowModel, which selects the entire row, including all columns.

If we execute the preceding code, we will have the following output:

Ext.grid.plugin.RowEditing

The RowEditing plugin enables editing in a particular row of the grid. When you click on the row, the editor (a form) will open and we can edit the row values:

Ext.create('Ext.grid.Panel', { renderTo: Ext.getBody(), frame: true, store: Contacts, width: 350, title: 'Contacts', selType: 'rowmodel', columns: [{ text: 'Name', flex: 1, dataIndex: 'name' },{ text: 'Email', flex: 1, dataIndex: 'email', editor: { xtype:'textfield', allowBlank:false } },{ text: 'Phone', flex: 1, dataIndex: 'phone', editor: { xtype:'textfield', allowBlank:false } }], plugins: [ Ext.create('Ext.grid.plugin.RowEditing', { clicksToEdit: 1 }) ] });

In the preceding code, we declared the RowEditing plugin in the plugins declaration. As in the CellEditing example, we also set clicksToEdit to 1, so the user will have to click only once on the row to open the editor.

We need to add the editor to the columns/cells; otherwise the column will not be editable, just like the CellEditing plugin.

We also highlighted the selType line in the preceding code. We set its value to rowmodel, meaning that, when we click on a row in the grid, the entire row will be selected, including all its columns.

When we execute the preceding code, we will have the following output:

Saving the data to the server

To save the data to the server, we need to change the Store to support the four CRUD (create, read, update, delete) actions, as follows:

var Contacts = Ext.create('Ext.data.Store', { model: 'Contact', proxy: { type: 'ajax', api: { read : 'contact/view.php', create : 'contact/create.php', update: 'contact/update.php', destroy: 'contact/delete.php' }, reader: { type: 'json', root: 'data', successProperty: 'success' }, writer: { type: 'json', writeAllFields: true, encode: false, root: 'data' } } });

We can also add a toolbar with Add and Delete buttons to the grid, to perform all the four CRUD operations:

var rowEditor = Ext.create('Ext.grid.plugin.RowEditing', { clicksToEdit: 1 }) var grid = Ext.create('Ext.grid.Panel', { //other config options plugins: rowEditor, dockedItems: [{ xtype: 'toolbar', items: [{ text: 'Add', handler : function() { rowEditor.cancelEdit(); // Create a record instance through the ModelMana var r = Ext.ModelManager.create({ name: 'New Contact', email: 'newcontact@email.com', phone: '1111-1111' }, 'Contact'); Contacts.insert(0, r); rowEditor.startEdit(0, 0); } },{ text: 'Delete', handler: function() { var sm = grid.getSelectionModel(); rowEditor.cancelEdit(); Contacts.remove(sm.getSelection()); if (store.getCount() > 0) { sm.select(0); } } }] }] });

And, if we want to, we can also create another button in the toolbar to save all our actions with the following code in the handler function:

Contacts.sync()

This way, we will save all the operations we performed on the grid, at once.

If we want to automatically save the data after every operation, we need to add the config option autoSync to the Store. However, this will generate a request to the server for every update, save, or delete action. If the user is going to perform many CRUD operations in the grid, autoSync may not be the best option; instead, the save handler function would be ideal.

Infinite scrolling

Ext JS 4 also introduces the infinite scrolling grid, used for rendering thousands of records without using the paging feature. If you worked with Ext JS 3 and tried to display a few thousands records at once, you know it took a big effort to make it work.

To implement an infinite scrolling grid, we just have to configure some properties in the Store and in the Grid. First, let's see how the Store looks:

Ext.define('Book', { extend: 'Ext.data.Model', fields: [ {name: 'book'}, {name: 'pages', type: 'int'} ] }); var store = Ext.create('Ext.data.Store', { id: 'store', pageSize: 50, buffered: true, purgePageCount: 0, model: 'Book', proxy: { type: 'ajax', url : 'data/infinite.json', reader: { type: 'json', root: 'data' } } }); store.guaranteeRange(0, 49);

In the preceding code snippet, we have a Model for book. We will display a book and its page number.

Then, we have a variable store and we configured three extra properties. The first one is pageSize (we have to configure this property to use it with paging), where we set how many records we will be buffering at once—we have to set the pageSize even if we are not going to use the paging feature. The second property that we configured is buffered, which is going to buffer and pre-fetch pages of records if we set it as true. The third property we set is the purgePageCount, which represents how many pages we are going to cache before purging more records. When we set its value to zero (0), it indicates that we are never going to purge pre-fetched data.

And finally, we call the guaranteeRange method, passing 0 and 49 (which is a number lower than the value of pageSize). This method will load the variable store with the specific number of records passed as the parameter and then will take care of any additional loading required to display the total number of records.

And finally, we have the grid declaration:

var grid = Ext.create('Ext.grid.Panel', { width: 400, height: 500, title: 'Bufffered Grid - 50k records', store: store, verticalScrollerType: 'paginggridscroller', invalidateScrollerOnRefresh: false, disableSelection: true, columns:[{ text: 'Book Name', flex:1 , sortable: true, dataIndex: 'book' },{ text: 'Pages', width: 125, sortable: true, dataIndex: 'pages' }], renderTo: Ext.getBody() });

We need to configure three additional properties to a simple grid to turn it into an infinite scrolling grid.

The first property is verticalScrollerType; in this case, we will set it as paginggridscroller/. The second one is invalidateScrollerOnRefresh, which, if set to false, will not refresh the scrollbar when we refresh the view. The third one is disableSelection, which we have to set as false, because the infinite grid does not support selection.

The preceding code will output the following grid:

Summary

This article covered some really important changes made to the grid package. Related to these component, we covered some new features, plugins, and API changes, using hands-on examples.


Further resources on this subject:


Ext JS 4 First Look A practical guide including examples of the new features in Ext JS 4 and tips to migrate from Ext JS 3 with this book and ebook.
Published: January 2012
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Loiane Groner

Loiane Groner lives in São Paulo, Brazil and has over 8 years of software development experience. While at university, she demonstrated great interest in IT. She worked as a teaching assistant for 2 and a half years specialising in teaching algorithms, data structures, and computing theory. She represented her university at the ACM International Collegiate Programming Contest, Brazilian Finals (South America Regionals), and also worked as Student Delegate of SBC (Brazilian Computing Society) for 2 years. She won a merit award in her senior year for being one of the top three students with the best GPAs in the Computer Science department and also graduated with honors.

She has already worked at multinational companies, such as IBM. Her areas of expertise include Java SE, Java EE, and also Sencha technologies (Ext JS and Sencha Touch). Nowadays, she is working as Software Development Manager at a financial institution, where she manages overseas solutions. She also works as an independent Sencha consultant and coach.

She has also authored books such as ExtJS 4 First Look and Mastering JS for Packt Publishing.

She is passionate about Sencha and Java, and is the CampinasJUG (Campinas Java Users Group) leader and ESJUG (Espirito Santo Java Users Group) coordinator, both Brazilian JUGs.

She also contributes to the software development community through her blogs: http://loianegroner.com (English) and http://loiane.com (Portuguese-BR), where she writes about IT careers, Ext JS, Sencha Touch, Spring Framework, and general development notes, and also publishes screencasts.

Books From Packt


Oracle Application Express 4.0 with Ext JS
Oracle Application Express 4.0 with Ext JS

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

Learning Ext JS
Learning Ext JS

Ext JS 3.0 Cookbook
Ext JS 3.0 Cookbook

Learning Ext JS 3.2
Learning Ext JS 3.2

iPhone JavaScript Cookbook
iPhone JavaScript Cookbook

Sencha Touch 1.0 Mobile JavaScript Framework
Sencha Touch 1.0 Mobile JavaScript Framework

Object-Oriented JavaScript
Object-Oriented JavaScript


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
k
U
c
p
L
1
Enter the code without spaces and pay attention to upper/lower case.
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