Tutorial: Creating an Ajax based form using Zend Framework and YUI

Many of you would already know that Dojo is JavaScript framework of the choice for Zend Framework. However, Zend framework itself is very loosely coupled that you can use whatever JavaScript framework you are comfortable in. As part of my previous project we were already using YUI, so it was the best idea that while Zend Framework was our choice for our next project, we should stick to the JavaScript framework in which we already have developed our expertise i.e. YUI. As part of developing an Ajax based form, it takes a bit of time to take your head around but it works exactly as the JavaScript should work with PHP i.e. unobtrusive way. The deal is simple, the whole point of using a MVC architecture is that, you have different layers of presentation, controlling and business logic, that makes your code easier to maintain and develop upon, same should be the case of JavaScript you will be using in your application. Just a note that I am using Zend Framework 1.10 for this mini-tutorial.

Let’s get to work!

Say you have a form in your forms directory which extends Zend_Form class:

<?php class Forms_Product_Values extends Zend_Form { public function init() { // Set the method for the display form to POST $this->setMethod('post'); $this->addElement('text','my_timestamp',array( 'filters'=>array('StringTrim'), 'required'=>true, 'label'=>'Time Stamp' )); $this->addElement('text','my_value',array( 'filters'=>array('StringTrim'), 'required'=>true, 'label'=>'Currency Value' )); // Add the submit button $this->addElement('button', 'values', array( 'ignore' => true, 'label' => 'Modify', )); } } ?>
In here, note the last element, button, normally if it is a non Ajax based form, the element type will be the submit but as we do not want the form to submit itself straight away, we would just like to create a button element and give it a name, in this case ‘values’, same as controller name, I will explain this later that why I have used this specific name in our tutorial.
Next you will create a corresponding controller action obviously to handle whatever you want to do with your form input:
public function valuesAction(){ $form = new Forms_Product_Values(); $request = $this->getRequest(); // Check to see if this action has been POST'ed to. if ($this->getRequest()->isPost()) { // Now check to see if the form submitted exists, and // if the values passed in are valid for this form. if ($form->isValid($request->getPost())) { //do whatever you want to do } } $this->view->form = $form; // disable layouts for this action: $this->_helper->layout->disableLayout();
}
and not values.phtml which will act as a view for our controller action:
<?=$this->form?>
OK, up to here it was simple, straight form without submit button in the form, now we need YUI to act here. You can either create a separate JS file (always recommended) or just paste your JavaScript code in the values.phtml (your view file) which is not recommended however, I am doing that just for demonstration purpose of this tutorial!
Here is you updated values.phtml:

<!-- Combo-handled YUI JS files: -->
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.8.1/build/yahoo-dom-event/yahoo-dom-event.js&2.8.1/build/connection/connection-min.js&2.8.1/build/selector/selector-min.js"></script>
<script type="text/javascript">
function fnCallback(e) {
sUrl = e.currentTarget.id; //controller name is the same as button name;
var nodes = YAHOO.util.Selector.query('input');
//prepare the data in query string format var data = ""; for (var i = 0; i< nodes.length; i++) { data += nodes[i].name+"="+nodes[i].value; if(i != nodes.length-1){ data += "&"; } }
var div = document.getElementById("responseDiv");
var handleSuccess = function(o) { //upon successful response we embed the response text into responseDiv on our HTML page div.innerHTML = o.responseText; YAHOO.util.Event.addListener("submitButton", "click", fnCallback); }; var handleFailure = function(o){ //if the request if failed, we need to log the event if(o.responseText !== undefined){ div.innerHTML = "Failed request to the server. Please try again."; } }; var handleEvent = { start:function(eventType, args){ }}; var callback = { //on start call back calls the handle event which starts showing ajax loader image customevents:{ onStart:handleEvent.start }, success:handleSuccess, //parameter to define which function to use on success failure:handleFailure, //parameter to define which function to use on failure timeout:1500 //timeout is 1500ms, can be extended from here }; var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, data); } function init(){ YAHOO.util.Event.addListener("values", "click", fnCallback); } YAHOO.util.Event.onDOMReady(init);
<div id="responseDiv">
<?=$this->form?>
</div>

See, no rocket science, however, couple of things to note, I am using a different approach here to remember controller name, I have assigned the same name to the button as the controller i.e. ‘values’, on click event the listener fires fnCallback function and then I read what is the id of the button, hence I know which controller is this and that is all I need as sUrl (the URL which I need to call, you may also need to concatinate “../../”+e.currentTarget.id),  another approach you can use is to echo the controller name in a hidden span or div in the view and then just read it from the JavaScript on click or if you can come up with any other approach, kindly post in comments of this tutorial for others to use.

Then is the YAHOO.util.Selector.query(‘input’), the beauty of YUI become handy here, as in this form I only have input elements I want to read, however, if you want to read say for example all the select and textarea elements, it is simple, just use this YAHOO.util.Selector.query(‘input’, ‘select’, ‘textarea’), now you know how to harvest your inputs from your form, you pull that on into the data variable and make the normal Ajax request through connection manager utility of YUI. The only bit remains here is, because your controller action is same, when you will send a request to it, your whole form will regenerate itself (which is intentional as in the controller I am actually making a database call and I want to show that whatever user has modified is actually in the database now) so you will loose the listener which you attached earlier to the button, you have to add it again on receiving the response, however, in this example, I have hard-coded it, you may want to send it dynamically with function call so that your function become totally dynamic and you could use same with all of your forms, I leave that upto you!

Happy Coding!

Leave a comment

4 Comments.

  1. First off… Thanks for this! But I’d wish that everyone who writes tutorials and posts code, would stop using short tags like <?=. It would save some time if I didn't have to replace them.

    The example doesn't work for me though. And I don't know why yet. I'll try to find out. It would help if you added a working online example or a screenshot. Then we would at least know what it's supposed to do.

    Thanks anyways!

  2. Boss khuda ka khof kroo…koi aisy chez likha kroo jo insaan smg b lay :razz:

  3. hahahaha waqas you are right bus wese guzra magaz se :twisted:

  4. First of all I want to thank you for sharing your thoughts and making the effort to create this blog post. But this is truly a bad way of coding. Everything is hacky and does NOT follow any of the MVC standards. There is no sign of RESTful. I really believe those who are trying to learn the language and the framework will get in a bad habit by just reading this post. Here are my marks:
    – You should not figure out your controller by the value of the submit button
    – Change:
    $request = $this->getRequest();
    if ($this->getRequest()->isPost())

    TO:
    $request = $this->getRequest();
    if ($request->isPost())
    – you should at least try to structure your valuesAction method to account for ajax calls and proceed with such functionality.

    I dont mean to be too critical but people would benefit more if a bit of time is put into the post.

    Thank you

Leave a Reply


[ Ctrl + Enter ]

Get Adobe Flash player