Handling Ajax requests in the Zend Framework
Friday, 26. October 2007, 16:57:17
Typically, in addition to the Ajax response, you need a traditional page response to a request as well - for example, for browsers which don't support Ajax.
Let's look at some methods how one can detect if a request is an Ajax request and how to respond to them in the Zend Framework.
Recognizing Ajax requests
First, we need to be able to detect that a request was an Ajax request to be able to properly respond them.
The most obvious method for achieving this would be to append something like ?ajax=1 as a GET parameter to the URL. This is probably the simplest and most sure to work method for doing this.
In your controller,
if($this->_request->getQuery('ajax') == 1)
{
//Ajax
}
You could also have separate actions in your controllers for ajax, but that wouldn't always be the best alternative as many Ajax requests require the same kind of data as normal ones do, so it could lead to code duplication. Of course, if your application does some more specialized Ajax things, then this is the best choice as this will efficiently separate your Ajax responses from the rest.
Zend Framework also provides a method in the Request-object that can be used to test this.
In your controller code,
if($this->_request->isXmlHttpRequest())
{
//The request was made with JS XmlHttpRequest
}
The isXmlHttpRequest function checks if the HTTP request header X_REQUESTED_WITH is set to XMLHttpRequest. This is not set automatically by browsers, so depending on your JavaScript code, it might not work. It does work with Prototype and Mootools at least, as I've used both of them in my projects.
Responding differently
If you are sharing actions for both normal and Ajax requests, you will probably want to send different data to to each.
- Full pages to normal requests
- Small HTML snippets, JSON or XML to Ajax
Using the methods I mentioned in the previous chapter, we can check if the request is Ajax. After this, it's just a matter of displaying a different view script to the user.
Manual view instantiation
$view->render('ajax.phtml');
With the ViewRenderer
$this->_helper->viewRenderer('ajax');
Outputting XML is quite simple with normal view scripts: Instead of HTML, you just write XML in your view script. The Zend Framework also makes it very easy to output JSON if needed:
//Disable ViewRenderer as we just want to output JSON
$this->_helper->viewRenderer->setNoRender();
//Some dummy data
$myArray = array(
'someData',
'moreData' => array(
'hello'
)
);
$jsonData = Zend_Json::encode($myArray);
$this->response->appendBody($jsonData);
What about layouts?
What if you're using layouts with the ViewRenderer?
You could run into a small problem: Even if you change the view script, it would still give you the layout code.
This can be fixed with a small predispatch plugin. You've probably used a plugin for checking user authentication against an Acl, but there are other uses too, like this one.
Instead of manually replacing the ViewRenderer with something else, or stopping the rendering, we can simply use a plugin to automatically replace the layout renderer with the default viewrenderer. This is pretty simple:
<?php
class AjaxCheckPlugin extends Zend_Controller_Plugin_Abstract
{
public function preDispatch($request)
{
//If the request is not an XHR, do nothing.
if(!$request->isXmlHttpRequest())
return;
$oldViewHelper = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$viewHelper = new Zend_Controller_Action_Helper_ViewRenderer($oldViewHelper->view);
Zend_Controller_Action_HelperBroker::addHelper($viewHelper);
}
}
?>
This plugin simply checks if the request is made with an XmlHttpRequest and replaces the viewrenderer with the default one. It also keeps the old view from the old viewrenderer. This is because if you assign some data to the view in your bootstrap, the data would be lost if we didn't re-assign the old view.
Adding this to the front controller is easy:
$fc = Zend_Controller_Front::getInstance(); $fc->registerPlugin(new AjaxCheckPlugin());
This is why I really like the Zend Framework: It provides you with many nice features such as the plugins which make doing things simple and easy.
Conclusion
So it's very easy to respond to Ajax if you know these few simple things.
Your technology is very clean, easy and understandable
By playpauseandstop, # 27. October 2007, 18:49:07
isXmlHttpRequest() also works with jQuery - although that header is only sent to the first request and if that redirects to a second url - then that header won't be sent. That is if I submit some data and then I want to have another URL to be shown, like if someone logs in successfully then I would like them to see the admin-interface - then the request redirected to the admin-interface won't contain the AJAX-header. At least when I tried to make something similar to what you've done and tested it in Firefox 2 :/
By anonymous user, # 28. October 2007, 09:02:13
Something like..
Then you can just use ?ajax=1 in your URLs and still keep using isXmlHttpRequest()
To use the above class, you could do something like this in your bootstrap:
Note that I didn't test it, but it should be something like that
By zomg, # 28. October 2007, 17:33:19
Thanks for sharing this! It's helped me a lot.
By anonymous user, # 18. April 2008, 04:49:13
I used AjaxCheckPlugin to disable Layout rendering.Does not work for me
By anonymous user, # 2. May 2008, 13:16:20
as of Zend 1.5 you can do this do disable the layout
public function installprocessAction()
{
$this->getHelper('layout')->disableLayout();
$this->getHelper('ViewRenderer')->setNoRender();
$myArray = array('hi');
$jsonData = Zend_Json::encode($myArray);
$this->getResponse()->setBody($jsonData);
}
By anonymous user, # 17. June 2008, 22:59:04
Nice thanx man. I'm learning Dojo at the moment. I've used ajax before but haven't got to the point of enhancing it is for my site which will be be on ZF :)
www.downstairzet.com
By anonymous user, # 14. September 2008, 00:14:13