Hide hidden Zend_Form elements
The Zend_Form has support for hidden elements, Zend_Form_Element_Hidden. In
default setup they are rendered in a <dt><dd>
wrapper and this can raise some
problems when applying styles to the form.
This blog article suggests a new idea to solve this problem. On the Internet many proposals are posted with all some drawbacks, which are solved in this idea.
By default a hidden element is rendered like this:
<dt><label for="element"></label></dt>
<dd><input type="hidden" name="element" id="element"></dd>
In this case the <dt>
is empty but occupies some space which you can’t remove
by applying css rules. Therefore you’d like to add, for example, a class to
the <dt>
so you can apply a display:none.
Most methods use the Zend_Form::render() method in which they loop through all elements and grab the elements of the type Zend_Form_Element_Hidden. One example is the suggestion of Tudor Barbu. There are two drawbacks of this example:
- You cannot reach the elements inside subforms
- You loop through all form elements, which is a huge performance impact
What then?
The case is actually quite simple. Instead of using the Zend_Form::render(), you apply only the class to the hidden elements itself. The Zend_Form_Element_Hidden extends the Zend_Form_Element, so Zend_Form_Element_Hidden uses also the (general) Zend_Form_Element::loadDefaultDecorators() method. When we create our own My_Form_Element_Hidden class, overriding the loadDefaultDecorators() method we can add some additional features to the default decorators.
<?php
class My_Form_Element_Hidden extends Zend_Form_Element_Hidden
{
/**
* Load default decorators
*
* @return void
*/
public function loadDefaultDecorators()
{
if ($this->loadDefaultDecoratorsIsDisabled()) {
return;
}
$decorators = $this->getDecorators();
if (empty($decorators)) {
$this->addDecorator('ViewHelper')
->addDecorator('Errors')
->addDecorator('Description', array('tag' => 'p', 'class' => 'description'))
->addDecorator('HtmlTag', array('tag' => 'dd',
'id' => $this->getName() . '-element'))
->addDecorator('Label', array('tag' => 'dt',
'class' => 'hidden'));
}
}
}
The only change made here is the added parameter ‘class’ => ‘hidden’ to the
label. Now the <dt>
gets a class hidden.
The last question is how we can initiate the My_Form_Element_Hidden instead of the Zend_Form_Element_Hidden. Zend_Form uses the elements by loading them like plugins. If we add our custom prefixPath to the form, Zend_Form will look into that path first and find our My_Form_Element_Hidden first. Other elements (like My_Form_Element_Text) are not found and the Zend_Form_Element_* classes will be loaded.
<?php
class My_Form extends Zend_Form
{
public function __construct($options = null)
{
$this->addPrefixPath('My_Form_', 'My/Form/');
parent::__construct($options);
}
}
Now we’re finished. We have a file library/My/Form.php to load the hidden
element automatically from our namespace. We also have a
library/My/Form/Element/Hidden.php to adjust the default decorators. We end up
with this html and can apply a css rule to hide the <dt>
line.
If you create your form, keep in mind you don’t need to extend the Zend_Form but your own My_Form. Then all hidden elements are hidden automatically (if the correct css is loaded), because the html is now like this:
<dt class="hidden"><label for="element"></label></dt>
<dd><input type="hidden" name="element" id="element"></dd>