📜 ⬆️ ⬇️

Ext JS 4 Grid "on the fingers"

Good afternoon, dear users.

Recently, I have been developing on Ext JS 4 and Zend framework 2.

Taking this opportunity, I would like to create a small series of articles "on the fingers" that illuminate some of the main components of Ext JS 4, without which no application on Ext JS can be done (sorry, series, - loudly said - I write from the sandbox).
')

So, Grid, part 1.


The Grid component allows you to create very flexible and functional tables with pagination, sorting, filtering, supporting unlimited nesting, templates, custom renderers, multiple plug-ins, event model, as well as all CRUD operations using ajax, rest, html5, cookies, sessions, and more.

In the first article I am going to look at all the basic principles of working with the grid (I tried to make all the examples as simple as possible, trying to ensure that not a single line of code could be removed from them).

The simplest table Ext.grid and Ext.data.ArrayStore


Ext.onReady(function() { var myData = [ ['3m Co', 71.72, 0.02, 0.03, '9/1 12:00am'], ['Alcoa Inc', 29.01, 0.42, 1.47, '9/1 12:00am'], //.................. ['Verizon Communications', 35.57, 0.39, 1.11, '9/1 12:00am'], ['Wal-Mart Stores, Inc.', 45.45, 0.73, 1.63, '9/1 12:00am'] ]; var store = Ext.create('Ext.data.ArrayStore', { fields: ['company','price','change','pctChange','lastChange'], data: myData }); Ext.create('Ext.grid.Panel', { store: store, columns: [ { text : 'Company', dataIndex: 'company' }, { text : 'Price', dataIndex: 'price' }, { text : 'Change', dataIndex: 'change' }, { text : '% Change', dataIndex: 'pctChange' }, { text : 'Last Updated', dataIndex: 'lastChange' } ], height: 350, width: 600, title: '   grid', renderTo: 'grid1' }); }); 

It is based on the most simplified example from the developers site .

To make this code work, create an index.html file (or any other) with the following contents:
 <!DOCTYPE html> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="/resources/css/ext-all.css" type="text/css" /> <script src="/ext-all.js" type="text/javascript"></script> <script src="/examples/grid1.js" type="text/javascript"></script> </head> <body> <p>  grid   Ext.data.ArrayStore</p> <div id="grid1"></div> </body> </html> 


I will not focus on this step. You can view the structure at the hub

Let's go back to the code!
Virtually every Ext JS 4 application starts with Ext.onReady (function () {...}. Those who use or use jQuery start their applications with something like: jQuery (document) .ready (function () {. ..}), - the goal of both records is to wait until the DOM and framework files load.

First of all, we created the usual non-associative two-level array myData with data directly in the code.

Then, using the Ext.create construction, we created an object of the Ext.data.ArrayStore class, a simple storage that allows working with ordinary javascript arrays, such as our myData.

The object can be created in a more usual way - using the operator new, for example new Ext.data.ArrayStore (...), but then we would have to manually load the file with the Ext.data.ArrayStore class.

Fortunately, in this case Ext.require construction is provided in Ext JS:

 Ext.require([ 'Ext.grid.*', 'Ext.data.*', ]); 

For example, you can load all class files for the Ext.grid and Ext.data scopes.

The task of the store object is to define the fields, a certain data structure and load this data itself.

The last step is to define the Ext.grid.Panel object.

In the Ext.grid.Panel constructor, we pass the Store object, - for working with data, in it we define the grid table columns and panel parameters:

The height (height), width (width), title (title) and id of the html-container (renderTo), where Ext JS will render our table.

That's all!

All that we have done is enough to create a simple Grid table that simply prints several rows with data and sorting by default.

Looking ahead, I note that the number of fields in the storage does not necessarily have to be equal to the number of columns in the grid — they only determine the structure of the data that can be output, in any way and where you want.

As a result of this script, we get the simplest static grid label:
image
Live demo

Replace Ext.data.ArrayStore with Ext.data.Store to make it easier to work with data.

Grid and Ext.data.Store


 Ext.onReady(function() { var myData = [ { company: 'Alcoa Inc', price: 71.72, change: 0.02, pctChange: 0.03, lastChange: '9/1 12:00am' }, { company: 'Altria Group Inc', price: 83.81, change: 0.28, pctChange: 0.34, lastChange: '9/1 12:00am' }, { company: 'American International Group, Inc.', price: 81.82, change: 0.12, pctChange: 0.63, lastChange: '9/1 12:00am' } ]; var store = Ext.create('Ext.data.Store', { fields: ['company','price','change','pctChange','lastChange'], data: myData }); var grid = Ext.create('Ext.grid.Panel', { store: store, columns: [ { text : 'Company', dataIndex: 'company' }, { text : 'Price', dataIndex: 'price' }, { text : 'Change', dataIndex: 'change' }, { text : '% Change', dataIndex: 'pctChange' }, { text : 'Last Updated', dataIndex: 'lastChange' } ], height: 350, width: 600, title: '   grid', renderTo: 'grid2' }); }); 

Now the data in myData is a collection of objects (hashes), with which we are going to work further.

On the screen, we see the same table (except that it has less data and it has a different title).

Now add the data model to our application.

Grid, Ext.data.Store and Ext.data.Model


 Ext.onReady(function() { var myData = [ { company: 'Alcoa Inc', price: 71.72, change: 0.02, pctChange: 0.03, lastChange: '9/1 12:00am' }, { company: 'Altria Group Inc', price: 83.81, change: 0.28, pctChange: 0.34, lastChange: '9/1 12:00am' }, { company: 'American International Group, Inc.', price: 81.82, change: 0.12, pctChange: 0.63, lastChange: '9/1 12:00am' } ]; Ext.define('Model', { extend: 'Ext.data.Model', fields: ['company','price','change','pctChange','lastChange'] }); var store = Ext.create('Ext.data.Store', { model: 'Model', data: myData }); var grid = Ext.create('Ext.grid.Panel', { store: store, columns: [ { text : 'Company', dataIndex: 'company' }, { text : 'Price', dataIndex: 'price' }, { text : 'Change', dataIndex: 'change' }, { text : '% Change', dataIndex: 'pctChange' }, { text : 'Last Updated', dataIndex: 'lastChange' } ], height: 350, width: 600, title: '   grid', renderTo: 'grid3' }); }); 

A few words about the model: if the Store is a collection of data, the model is one copy of this data. At first glance, the model may seem redundant, but without it we will not be able to work with multi-level nested data in an easy way.

It's time to get rid of storing data in the code, for this we need a proxy .

Grid and proxy


 Ext.onReady(function() { Ext.define('myModel', { extend: 'Ext.data.Model', fields: ['company','price','change','pctChange','lastChange'] }); var store = Ext.create('Ext.data.Store', { model: 'myModel', proxy: { type: 'ajax', url: '/examples/data/data.json', reader: { type: 'json', root: 'data' } }, autoLoad: true }); var grid = Ext.create('Ext.grid.Panel', { store: store, columns: [ { text : 'Company', dataIndex: 'company' }, { text : 'Price', dataIndex: 'price' }, { text : 'Change', dataIndex: 'change' }, { text : '% Change', dataIndex: 'pctChange' }, { text : 'Last Updated', dataIndex: 'lastChange' } ], height: 350, width: 600, title: '   grid', renderTo: 'grid4' }); }); 

From this point on, the most interesting thing begins - we removed the hard-coded data from our grid table and defined the proxy in our repository.

The proxy object makes it very convenient to perform any CRUD procedures using ajax, rest, or local storages at the abstract level, using special readers to decrypt data (for more details, see the next article).

We will use ajax proxy, which automatically (autoLoad: true) will load the data to the specified url address (the default request is executed by the GET method), and the specified reader will try to decrypt it from the json format. root: 'data' indicates to the reader that the root node with data has the key "data".

The important point is that, by default, the grid displays only 25 lines. To fix this, you need to add the pageSize property to the initialization of our repository, like this:
  var store = Ext.create('Ext.data.Store', { model: 'myModel', pageSize: 50, proxy: { type: 'ajax', url: '/examples/data/data.json', reader: { type: 'json', root: 'data' } }, autoLoad: true }); 


To enable pagination in the grid table, it is enough to add the Ext.PagingToolbar object to the grid initialization in some “toolbar”, for example in bbar :
  var grid = Ext.create('Ext.grid.Panel', { store: store, columns: [ { text : 'Company', dataIndex: 'company' }, { text : 'Price', dataIndex: 'price' }, { text : 'Change', dataIndex: 'change' }, { text : '% Change', dataIndex: 'pctChange' }, { text : 'Last Updated', dataIndex: 'lastChange' } ], height: 350, width: 600, title: '   grid', renderTo: 'grid5', bbar: Ext.create('Ext.PagingToolbar', { store: store }) }); 


Now we have pagination:
image
Live demo

I’ll draw your attention to the fact that all columns of Grid tables by default support local sorting, unless otherwise specified. If it is necessary to sort the data on the server, you need to specify this in our repository using the “remoteSort: true” property:

 Ext.onReady(function() { Ext.define('myModel', { extend: 'Ext.data.Model', fields: ['company','price','change','pctChange','lastChange'] }); var store = Ext.create('Ext.data.Store', { model: 'myModel', proxy: { type: 'ajax', url: '/examples/data/data.json', reader: { type: 'json', root: 'data' } }, autoLoad: true, remoteSort: true }); var grid = Ext.create('Ext.grid.Panel', { store: store, columns: [ { text : 'Company', dataIndex: 'company' }, { text : 'Price', dataIndex: 'price' }, { text : 'Change', dataIndex: 'change' }, { text : '% Change', dataIndex: 'pctChange' }, { text : 'Last Updated', dataIndex: 'lastChange' } ], height: 350, width: 600, title: '   grid', renderTo: 'grid6', bbar: Ext.create('Ext.PagingToolbar', { store: store }) }); }); 


Now, when trying to sort, you can see the following picture in firebug:
image

Now let's see how data filtering can be implemented.

Filters in grid tables


 Ext.Loader.setPath('Ext.ux', '/public/ux'); Ext.require([ 'Ext.ux.grid.FiltersFeature', ]); Ext.onReady(function() { Ext.define('myModel', { extend: 'Ext.data.Model', fields: ['company','price','change','pctChange','lastChange'] }); var store = Ext.create('Ext.data.Store', { model: 'myModel', proxy: { type: 'ajax', url: '/public/examples/data/data.json', reader: { type: 'json', root: 'data' } }, autoLoad: true, remoteSort: true }); var filters = { ftype: 'filters', encode: true, local: false }; var grid = Ext.create('Ext.grid.Panel', { store: store, features: [filters], columns: [ { text : 'Company', dataIndex: 'company', filter: { type: 'string' } }, { text : 'Price', dataIndex: 'price', filter: { type: 'int' } }, { text : 'Change', dataIndex: 'change', filter: { type: 'float' } }, { text : '% Change', dataIndex: 'pctChange', filter: { type: 'float' } }, { text : 'Last Updated', dataIndex: 'lastChange', filter: { type: 'date' } } ], height: 350, width: 600, title: '  grid  ', renderTo: 'grid8', bbar: Ext.create('Ext.PagingToolbar', { store: store }) }); }); 

For the first time in the code of our grid table, an entry appeared:
 Ext.Loader.setPath('Ext.ux', '/public/ux'); Ext.require([ 'Ext.ux.grid.FiltersFeature', ]); 

This entry causes Ext JS to load the Ext.ux.grid.FiltersFeature class from the / public / ux / grid directory, which is required for the filters in the grid table.

Another new feature is the initialization of the filters object containing the configuration of our filters:
 var filters = { ftype: 'filters', encode: true, local: false }; 

Here we are interested in the properties of encode and local. As you probably already guessed, the local: false property causes the filter values ​​to be sent to the server, and encode: true allows you to get the filter data on the server as an array, rather than json strings.

So, the filtering is configured, it remains to specify in the columns of the table: which filter to use the column:
 filter: { type: 'string' } 

In our example, filters are used: string, int, float and date, - the work of each of them can be seen by clicking on the column heading in the table, selecting the Filters element
and specify its value, then the onChange event will trigger the table data will be updated. You can see in firebug how Ext JS performs an ajax request to the server.
image
Live demo (sorry, the data does not change when using filters, - the front end is cached into the trash, because I'm afraid of the habra effect)

Concluding the article, I want to embellish our table a little.

First, we indicate the types for the fields in the model:
 fields: [ {name: 'weight', type: 'int'}, {name: 'company', type: 'string'}, {name: 'price', type: 'float'}, {name: 'change', type: 'float'}, {name: 'pctChange', type: 'float'}, {name: 'lastChange', type: 'string'} ] 


Secondly, it’s enough to request GET data:
 Ext.create('Ext.data.Store', { pageSize: 10, model: 'myModel', proxy: { type: 'ajax', url: '/examples/data/data2.json', actionMethods: { read: 'POST' }, reader: { type: 'json', root: 'data', totalProperty: 'totalCount' } }, autoLoad: true, remoteSort: true }); 


Let's make the table columns with rubber:

 { text : '% Change', flex:1, dataIndex: 'pctChange' }, 


Let's try to create a storage object implicitly:
 store: Ext.data.StoreManager.lookup('gridStore'), 


Let's create the simplest handler for displaying the grid column - let it seem naive.
 renderer: function(value){ if(value > 75){ value = '<span style="color:#ff0000;">' + value + '</span>'; } else { value = '<span style="color:#00ff00;">' + value + '</span>'; } return value; } 


And lastly, we will add information about the total number of table entries to our paginator:
 bbar: Ext.create('Ext.PagingToolbar', { store: store, displayInfo: true, displayMsg: 'Displaying topics {0} - {1} of {2}', emptyMsg: "No topics to display" }) 

(data about the total amount come to json, as indicated in the totalProperty in our repository).

Putting it together:
 Ext.Loader.setPath('Ext.ux', '/ux'); Ext.require([ 'Ext.ux.grid.FiltersFeature', ]); Ext.onReady(function() { Ext.define('myModel', { extend: 'Ext.data.Model', fields: [ {name: 'weight', type: 'int'}, {name: 'company', type: 'string'}, {name: 'price', type: 'float'}, {name: 'change', type: 'float'}, {name: 'pctChange', type: 'float'}, {name: 'lastChange', type: 'string'} ] }); Ext.create('Ext.data.Store', { pageSize: 10, model: 'myModel', proxy: { type: 'ajax', url: '/examples/data/data2.json', actionMethods: { read: 'POST' }, reader: { type: 'json', root: 'data', totalProperty: 'totalCount' } }, autoLoad: true, remoteSort: true }); var filters = { ftype: 'filters', encode: true, local: false }; var grid = Ext.create('Ext.grid.Panel', { store: Ext.data.StoreManager.lookup('gridStore'), features: [filters], columns: [ { text : 'Weight', dataIndex: 'weight', width: 50, sortable: false, filter: { type: 'int' } }, { text : 'Company', dataIndex: 'company', flex:1, filter: { type: 'string' } }, { text : 'Price', dataIndex: 'price', flex:1, renderer: function(value){ if(value > 75){ value = '<span style="color:#ff0000;">' + value + '</span>'; } else { value = '<span style="color:#00ff00;">' + value + '</span>'; } return value; } }, { text : 'Change', flex:1, dataIndex: 'change' }, { text : '% Change', flex:1, dataIndex: 'pctChange' }, { text : 'Last Updated', flex:1, dataIndex: 'lastChange', filter: { type: 'date' } } ], height: 350, width: 600, title: ' ...', renderTo: 'grid9', bbar: Ext.create('Ext.PagingToolbar', { store: store, displayInfo: true, displayMsg: 'Displaying topics {0} - {1} of {2}', emptyMsg: "No topics to display" }) }); }); 


and we see a beautiful grid table with sorting and filtering on the server, pagination and the simplest custom-renderer:
image

Afterword.


Dear users, I really hope for your loyalty - this is my first article. Dear UFO, - I apologize for the repost of my article, originally wrote for Habr, but I wanted to throw a link to the demo (and one more thing). About inaccuracies, jambs, comments, requests, etc. please write in a personal. If someone interested in this article, I will be happy to continue to write on Ext JS 4, - in plans to write an article-continuation on Ext JS grid (plug-ins. Templates, events, a bundle with propertygrid, CRUD and readers ...), as well as highlight other aspects of the Ext JS 4 framework. Thank you for your attention.

Source: https://habr.com/ru/post/169125/


All Articles