Friday, May 28, 2010

Tabbed Forms, Part 2

In the previous article, I described how to create a simple tabbed form. The code for this form contained submit elements on each page. In this article I will describe how to create a tabbed form with a submit element that is outside of the tabs.

If you remember from before, the form decorators were set up like this:
$form->setDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'div', 'id'=>'tabContainer', 'class'=>'mainForm')),
array('TabContainer', array('id'=>'tabContainer', 'style'=>'width: 530px;')),
'Form'
));
If you understand how decorators work, you know that they are rendered in reverse order. So the Form decorator generates the outtermost div, then the TabContainer decorator, then the HtmlTag decorator, and finally the FormElements. With this structure, all the form elements are rendered inside the tab container.

What we want is to render some additional elements outside the tab container, so we would like to use a decorator structure like this:
$form->setDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'div', 'id'=>'tabContainer', 'class'=>'mainForm')),
array('TabContainer', array('id'=>'tabContainer', 'style'=>'width: 530px;')),
'FormElements',
'Form'
));
Unfortunately, each decorator alias can only be used once in the chain. This note in the ZF documentation explains:

Internally, Zend_Form uses a decorator's class as the lookup mechanism when retrieving decorators. As a result, you cannot register multiple decorators of the same type; subsequent decorators will simply overwrite those that existed before. To get around this, you can use aliases. Instead of passing a decorator or decorator name as the first argument to addDecorator(), pass an array with a single element, with the alias pointing to the decorator object or name.

Well, that's a bit confusing, you might think the following decorator set would work, but it doesn't:
$form->setDecorators(array(
array('SubformElements'=>'FormElements'),
array('HtmlTag', array('tag' => 'div', 'id'=>'tabContainer', 'class'=>'mainForm')),
array('TabContainer', array('id'=>'tabContainer', 'style'=>'width: 530px;')),
'FormElements',
'Form'
));
This one does, though:
$form->setDecorators(array(
array('decorator' => array('SubformElements'=>'FormElements')),
array('HtmlTag', array('tag' => 'div', 'id'=>'tabContainer', 'class'=>'mainForm')),
array('TabContainer', array('id'=>'tabContainer', 'style'=>'width: 530px;')),
'FormElements',
'Form'
));
So here is the new code for our createTabbedForm function, with the submit button included outside the tab container:
/**
* You must set the form id so that you can add your tabPanes to the tabContainer
*/
$form = new ZendX_JQuery_Form;
$form->setAttrib('id', 'mainForm');

/**
* Add your form elements first, before setting the decorators
*/
$form->addElement('submit', 'Submit');

/**
* Use the TabContainer View Helper
* Use both FormElements and SubformElements to render elements inside and outside the tabs
*/
$form->setDecorators(array(
array('decorator' => array('SubformElements'=>'FormElements')),
array('HtmlTag', array('tag' => 'div', 'id'=>'tabContainer', 'class'=>'mainForm')),
array('TabContainer', array('id'=>'tabContainer', 'style'=>'width: 530px;')),
'FormElements',
'Form'
));

/**
* Create the subforms and add some elements
*/
$subforms = array();
$subforms[0] = new ZendX_JQuery_Form;
$username = $form->createElement('text', 'username')
->setLabel('username');
$subforms[0]->addElement($username);

$subforms[1] = new ZendX_JQuery_Form;
$guestname = $form->createElement('text', 'guestname')
->setLabel('guestname');
$subforms[1]->addElement($guestname);

/**
* Set the decorators on the subforms to use TabPane View Helper
* Note that containerId is the same as the form id set earlier
*/
foreach ($subforms as $pageno=>$subform) {
$subform->setAttrib('id', 'subForm');
$subform->setDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'div', 'class' => 'subForm')),
array('TabPane', array('jQueryParams' =>
array('containerId' => 'mainForm', 'title' => 'Page '.$pageno))),
'Form'
));
$form->addSubform($subform, 'subform_'.$pageno);
}

return $form;
Happy coding!

No comments:

Post a Comment