Creating an Ext JS grid using the Zend Framework
by Naneau
Web development has become a lot easier with the rise of frameworks and libraries that help you with common tasks. On the server side there’s PEAR, CakePHP, Symfony and the Zend Framework, amongst others. For the client you can choose from YUI, Prototype, Scriptaculous, Ext JS and many, many more. All these libraries and frameworks have some kind of philosophy behind them, and look at things slightly differently. There is no “best” framework, they all have their pros and cons. Today I’m going to use two of the ones I like and create a nice little grid. Take a look at the demo to see the end result.
The grid component from ExtJS looks difficult, the first time you look at it. There are many things you can configure, and they’re not all documented that well. Trying to keep in line with previous entries on naneau.nl, I’m going to use the grid to display a number of blog posts. I’ve based much of the javascript code on the paging example you can find in the Ext JS documentation.
The basis of an Ext JS Grid is data, of course. It stores it’s data in a Store. There are a few ways of getting data into the store. There’s a memory reader, which I have used in a previous post. Today I’m going to be using a HttpProxy to access my data, which the server will return in JSON format.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | var ds = new Ext.data.Store({ proxy: new Ext.data.HttpProxy({ url: 'http://localhost/index/list/' //change this! }), reader: new Ext.data.JsonReader({ root: 'posts', totalProperty: 'count', id: 'id' }, [ {name: 'title', mapping: 'title'}, {name: 'timestamp', mapping: 'timestamp', type: 'date', dateFormat: 'timestamp'}, {name: 'contents', mapping: 'contents'} ]), remoteSort: true }); ds.setDefaultSort('timestamp', 'desc'); |
Notice how I’ve turned on remote sorting, and set a default sort. We will come back to that later, in the controller that will give us our data. The next thing Ext JS wants is something it calls a ‘Column Model’. Basically it’s a set of columns that the grid should contain. You can specify functions that it uses to render the contents of the cells of a specific column, so you can make data look nicer.
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 | function renderDate(value, p, r){ return String.format('{0}', value.dateFormat('M j, Y, g:i a')); } function renderPost(value, p, record) { var post = record.data['contents'].replace(/(<([^>]+)>)/ig,""); //strip html if (post.length > 200) { post = post.substr(0,200) + ' [...]'; //shorten it } return String.format('<p><b>{0}</b><br />{1}</p>', value, post); } var cm = new Ext.grid.ColumnModel([{ header: "Post", dataIndex: 'title', width: 530, renderer: renderPost, css: 'white-space:normal;' },{ header: "Date", dataIndex: 'timestamp', width: 150, renderer: renderDate }]); cm.defaultSortable = true; |
As you can see I have written two little functions to display two kinds of cells. The post has a title in bold, and a substring of it’s contents below it. The date in unix timestamp format will be parsed into something humans can read using dateFormat(). By making defaultSortable true, all the columns can be sorted by default, which is one of the nicest features of the Ext JS Grid, in my opinion.
The actual grid is now easy to create:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var grid = new Ext.grid.Grid('grid-example', { ds: ds, cm: cm, selModel: new Ext.grid.RowSelectionModel({singleSelect:true}), enableColLock:false, loadMask: true }).render(); //the grid itself var gridFoot = grid.getView().getFooterPanel(true); var paging = new Ext.PagingToolbar(gridFoot, ds, { pageSize: 10, displayInfo: true, displayMsg: 'Displaying posts {0} - {1} of {2}', emptyMsg: 'No posts to display' }); //create a paging footer ds.load({params:{start:0, limit:10}}); //start loading data from the server |
There should be a matching container in your HTML somewhere, with an id “grid-example”, this will be the container for the grid. You should give this a width and height, and hide it’s overflow.
1 2 3 4 5 | #grid-example { width:700px; height:300px; overflow:hidden; } |
That’s all for the client side. For those of you that come from a PHP background this may seem difficult, while it’s really not. But just in case it’s too scary for you, I’m only going to be looking at juicy php scripts from now on. The HttpProxy from Ext JS will do a request every time it needs data for it’s grid. With it it will send a http post string like:
1 | start=10&limit=10&sort=title&dir=ASC |
We can use the variables from that string to create a simple controller action:
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 | public function listAction() { $offset = (isset($_POST['start'])) ? $_POST['start'] : 0; $limit = (isset($_POST['limit'])) ? $_POST['limit'] : 10; $sort = (isset($_POST['sort'])) ? $_POST['sort'] : 'id'; $dir = (isset($_POST['dir'])) ? $_POST['dir'] : 'ASC'; //request data, do some kind of validation on this Zend_Loader::loadClass('Post'); $pM = new Post(); //post model $return = array(); //return array $return['posts'] = $pM->fetchAll(null, array($sort . ' ' . $dir), $limit, $offset)->toArray(); //the posts $return['count'] = $pM->getAdapter()->fetchOne('SELECT count(*) FROM post'); //total number of posts Zend_Loader::loadClass('Zend_Json'); $json = Zend_Json::encode($return); //result encoded in JSON $this->getResponse()->setHeader('Content-Type', 'text/javascript'); $this->getResponse()->setBody($json); //encode result and pass it back } |
The Post class I use in this example extends Zend_Db_Table. The only thing you have to remember is that the grid expects both a ‘posts’ bit in the return array and a ‘count’ bit. This corresponds with the JSON reader from the data store:
1 2 3 4 5 | reader: new Ext.data.JsonReader({ root: 'posts', totalProperty: 'count', id: 'id' } |
That wasn’t too hard, was it? And the result is just… beautiful! You can of course view the complete JavaScript used.
Comments
Well, where have I to include the javascript for the correct render? Or better how can use a view for rendering the table?
thank in advance for the hints.
You must make sure that you have all the necessary javascript files loaded in the head of your html file. See the INCLUDE_ORDER.txt file that comes with ExtJS to see in what order you should do that. If you have everything loaded, you can put the javascript that builds the table directly into your head, or put it in a separate file as well (just make sure it’s _after_ the ExtJS stuff in your html head section).
Thanks for the quick response!
All the javascript are loaded fine. I’m tryng to use a view for rendering, and in my controller (listAction) after $this->getResponse()->setBody($json, ‘post’) I set $this->render(); and I create list.phtml for rendering
But this is not the right way
you don’t have to explicitly call $this->render() in your controller actions. Just make sure you set a body. Can you output just plain html? Don’t forget to encode your result as JSON using Zend_JSON.
Thanks! Excellent post! Could you please put all working code together into a ZIP or TAR file in a download area?
Thanks.
Hi,
loved the article… tried printing it, but the textareas don’t really agree. Maybe a good idea to add a “print” button with a link to a printer friendly page? Love your blog for the rest
Jeroen
Hi,
first thanks for your article, really interesting. I still have a problem to render the grid. The encoding of the data in JSON works good, but if i try to open the grid with http://localhost/ and the html code in index.phtml in the right view directory nothing happens. If i put the same code in a local directory it works fine. The source code in the browser is in both cases the same. Where is the problem?
Thanks in advance for your help.
var colModel1 = new Ext.grid.ColumnModel([
new Ext.grid.RowNumberer(), //行号列,
sm,
{
header:'',
width:100,
sortable:true,
hideable:false,
dataIndex:'',
editor: new Ext.form.TextField({
allowBlank: false,
blankText:'not null!'
})
}
,
]);
how can i do other validation for the column?????
”
var colModel1 = new Ext.grid.ColumnModel([
new Ext.grid.RowNumberer(), //行号列,
sm,
{
header:'',
width:100,
sortable:true,
hideable:false,
dataIndex:'',
editor: new Ext.form.TextField({
allowBlank: false,
blankText:'该字段必须输入!'
})
}
,
]);
“
[...] Creating an Ext JS grid using the Zend Framework [...]
hi can someone give me plz a download link
or is there a subversion link?
[...] Admin: usar MVC y migrar las vistas con Zend_Form a interfaces de ExtJs. Ref: “Creating Extjs grid with ZF” by [...]
Hi,
I’ve been working with zend framework with php.
Now I would like to work with AJAX with zend framework. Can you please help on this? I don’t know how to create ajax request in Zend framework.