To be honest, I’ve just started to work with the CakePHP+extJs combination.
But I’m using Cake for almost a year now.
When I was trying out this powerful combination I’ve decided to improve the end result of the „CakePHP 15 minutes blog example” with extJs.
At least, the index function.
For this tiny tutorial I assume, that you have completed the blog tutorial right now, and you have all the controllers, views, and models.
The JSON version of this example is available here.
So I’ve inserted there lines to the head part of my default layout:
<link rel="stylesheet" type="text/css" href="/js/ext/resources/css/ext-all.css" /> <script src="/js/ext/adapter/ext/ext-base.js" type="text/javascript"></script> <script src="/js/ext/ext-all.js" type="text/javascript"></script> <script type="text/javascript" src="/js/RowExpander.js"></script> <script src="/js/<?php echo $_name; ?>-<?php echo $_action; ?>.js" type="text/javascript"></script> |
But for this I need the $this->name, and $this->action variable assigned as $_name, and $_action.
I do it in app/app_controller.php like this:
function beforeRender() { $this->set('_name',strtolower($this->name)); $this->set('_action',strtolower($this->action)); } |
Now I need to copy the ext library to /app/webroot/js/ext, and create the /app/webroot/js/posts-index.js there.
My posts-index.js contains this:
/* * Ext JS Library 2.0 * Copyright(c) 2006-2007, Ext JS, LLC. * licensing@extjs.com * * http://extjs.com/license */ Ext.onReady(function(){ Ext.QuickTips.init(); var xg = Ext.grid; // create the Data Store var store = new Ext.data.Store({ // load using HTTP url: '/posts/xml', // the return will be XML, so lets set up a reader reader: new Ext.data.XmlReader({ // records will have an "Item" tag record: 'item', id: 'id', totalRecords: '@total' }, [ // set up the fields mapping into the xml doc // The first needs mapping, the others are very basic {name: 'title', mapping: 'itemattr > title'}, 'id', 'body', 'created', 'modified' ]) }); // expander cucc var expander = new xg.RowExpander({ tpl : new Ext.Template( '<b>Body:</b><br />', '<p>{body}</p>' ) }); var sm = new xg.CheckboxSelectionModel(); var grid = new xg.GridPanel({ id:'button-grid', store: store, cm: new xg.ColumnModel([ expander, sm, {header: "Id", width: 5, sortable: true, dataIndex: 'id'}, {header: "Title", width: 20, sortable: true, dataIndex: 'title'}, {header: "Created", width: 20, sortable: true, dataIndex: 'created'}, {header: "Last Updated", width: 20, sortable: true, dataIndex: 'modified'} ]), sm: sm, viewConfig: { forceFit:true }, // inline buttons buttons: [{text:'Save'},{text:'Cancel'}], buttonAlign:'center', // inline toolbars tbar:[{ text:'Add Post', tooltip:'Add a new post', handler: function() { location.href='/posts/add'; }, iconCls:'add' }], plugins: expander, width:600, height:300, frame:true, title:'Posts', iconCls:'icon-grid', renderTo:'content' }); store.load(); }); |
Please notice the „url” attribute in line 18. It refers to /posts/xml, so I need to create the controller, a view, and a separate layout for that.
First I’ve created the xml.thtml layout in ‘/app/views/layouts/’, what contains this:
<?php header('Content-Type: text/xml; charset=utf-8'); echo $content_for_layout; ?> |
And the xml.thtml in ‘/app/views/posts’
So xml.thtml will look like this:
<?xml version="1.0" encoding="UTF-8"?> <items> <?php foreach($posts as $post): ?> <item> <id><?php echo $post[Post][id]; ?></id> <itemattr> <body><?php echo $post['Post']['body']; ?></body> <created><?php echo $post['Post']['created']; ?></created> <modified><?php echo $post[Post][modified]; ?></modified> </itemattr> </item> <?php endforeach; ?> </items> |
And in the posts_controller.php out new xml function will look like this:
function xml() { $this->layout='xml'; $this->set('posts', $this->Post->findAll()); } |
We are almost ready now.
You need to truncate your posts/index.thtml because extJs will render everything in the „content” div (where the views rendered generaly), so it’s better, to be blank.
There’s one more thing.
In my example I refer to ‘RowExpander.js’ from the ‘ext/examples/grid’ directory. So I’ve copied it to /js directory.
And I guess we are ready 🙂
( Most of my codes are written to used together with Smarty. For this explanation I rewrite it to be used as original cake thtml. )
Thanx fot the Tutorial, I would like to know How can I do this with a Json reader and if Json reader is faster than the XML reader?
@boris – you can find a json example here: http://www.ntatd.org/mark/?p=30.
@djzone – if you include your javascript file in the default layout, what happens if you have an action with no associated javascript file? I include the appropriate javascript files at the end of my views. That way, actions that don’t have a javascript file don’t try to load them.
hydra12, the webserver will throw a 404 error. It won’t hurt.
Hi, djZone,
are you calling the js files, and the css files using the cakephp helpers , or are you just declaring them in plain HTML code?
because, there is a chance that you move your directories to a different location / server, and they might not get called. I hate modifying my codes when moving them to different location.
Well I guess, you can add aliases to you JS libraries in routes.php, if you want.
And it won’t hurt if you move, your files 🙂
Awesome! Brilliant sharing really I love both cake and ExtJS … amazing tutorial keep sharing such nice tutorials I’ll really love more things on cake with extJS!
This was great information! Thank you! I was able to take your sample code for the add button and integrate it into my project. Once I took the leading ‘/’ off (as in location.href=’groups/add’) it worked very well.
Now… how do I do the same in a simple grid but for an edit button? The user has selected a row and now presses the edit button. How do I code the handler for that?
Thanks for your help!