views:

1816

answers:

2

I have 2 requirements: 1) All hidden input elements should be affected without removing standard decorators. 2) This should happen WITHOUT having to specify it on a per-element basis.

All I need is for a CSS class to be attached to the DT & DD tags IF the element type is Zend_Form_Element_Hidden.

I've tried creating custom HtmlTag, DtDdWrapper, and FormElement decorators, but haven't been able to figure out how to do it.

By default they appear this way:

<dt>&nbsp;</dt>
<dd><input type="hidden" name="whatever" value="bling" /></dd>

I would like them to appear this way:

<dt class="hidden">&nbsp;</dt>
<dd class="hidden"><input type="hidden" name="whatever" value="bling" /></dd>

That way they'll still be where they should be, but they won't interrupt the flow of the document.

Example of what didn't work:

class My_Form_Decorator_DtDdWrapper extends Zend_Form_Decorator_DtDdWrapper
{
    public function render($content)
    {
        if ($this->getElement() instanceof Zend_Form_Element_Hidden)
        {
            return '<dt class="hidden">&nbsp;</dt><dd class="hidden">'.$content.'</dd>';
        }
        else
        {
            return parent::render($content);
        }
    }
A: 

This will help you : You may also specify any other attributes.

$el = $form->getElement('whatever');
$el->addDecorators(
            array('ViewHelper',
            array('HtmlTag',array('tag' => 'dt','class'=>'hidden')),
            array('Label', array('tag' => 'dd ',  'class'=>'hidden')),
            ));
waney
I saw that in the documentation, but it meets neither of my two requirements :( Thanks for trying, though.
lo_fye
+2  A: 

Based on your desired sample output I'm unclear why you would want to include the <dt> on hidden elements, especially since you're not applying any label, they end up becoming needless markup. Following the assumption that the label is unnecessary, you can achieve the desired effect with the following:

class TestForm extends Zend_Form
{
    protected $_hiddenElementDecorator = array(
        'ViewHelper',
        array('HtmlTag', array('tag' => 'dd', 'class' => 'hidden')),
    );

    public function init()
    {
        $this->addElement('hidden', 'hiddenElement0');

        $element = new Zend_Form_Element_Hidden('hiddenElement1');
        $this->addElement($element);

    }

    public function loadDefaultDecorators()
    {
        foreach ($this->getElements() as $element) {
            if ($element->getType() === "Zend_Form_Element_Hidden") {
                $element->setDecorators($this->_hiddenElementDecorator);
            }
        }

        parent::loadDefaultDecorators();
    }
}

Both of the above elements will result in the same output with their respective id's. Example:

<dd class="hidden">
    <input type="hidden" name="hiddenElement0" value="" id="hiddenElement0" />
</dd>

The foreach loop in the loadDefaultDecorators() method iteratively applies $this->_hiddenElementDecorator to each hidden form element when the form is built. If you want to apply the hidden element decorator on multiple forms, just create a parent class with the $_hiddenElementDecorator variable and loadDefaultDecorators() method in it.


However, if you have your heart set on including the label element (<dt>) as described in your sample output and applying the 'hidden' class so you end up with:

<dt class="hidden">&nbsp;</dt>
<dd class="hidden">
    <input type="hidden" name="hiddenElement0" value="" id="hiddenElement0" />
</dd>

... you will need to extend the Zend_Form_Decorator_Label class and override the render() method. Take a look at the comment in the if (null !== $tag) block:

class My_Form_Decorator_Label extends Zend_Form_Decorator_Label
{
    public function render($content)
    {
        $element = $this->getElement();
        $view    = $element->getView();
        if (null === $view) {
            return $content;
        }

        $label     = $this->getLabel();
        $separator = $this->getSeparator();
        $placement = $this->getPlacement();
        $tag       = $this->getTag();
        $id        = $this->getId();
        $class     = $this->getClass();
        $options   = $this->getOptions();

        if (empty($label) && empty($tag)) {
            return $content;
        }

        if (!empty($label)) {
            $options['class'] = $class;
            $label = $view->formLabel($element->getFullyQualifiedName(), trim($label), $options);
        } else {
            $label = '&nbsp;';
        }

        if (null !== $tag) {
            require_once 'Zend/Form/Decorator/HtmlTag.php';
            $decorator = new Zend_Form_Decorator_HtmlTag();
            // Add 'class' => 'hidden' to the <dt> tag decorator options.
            $decorator->setOptions(array('tag' => $tag, 'class' => 'hidden'));
            $label = $decorator->render($label);
        }

        switch ($placement) {
            case self::APPEND:
                return $content . $separator . $label;
            case self::PREPEND:
                return $label . $separator . $content;
        }

    }
}

Finally, to apply your new decorator to all of the hidden form elements you will need to add the an element prefix path point to your decorator and re-add the label decorator to the $_hiddenElementDecorator array in the TestForm class:

class TestForm extends Zend_Form
{
    protected $_hiddenElementDecorator = array(
        'ViewHelper',
        array('HtmlTag', array('tag' => 'dd', 'class' => 'hidden')),
        // Add back the label element.
        array('Label', array('tag' => 'dt', 'class' => 'hidden')),
    );

    public function init()
    {
        $this->addElement('hidden', 'hiddenElement0');

        $element = new Zend_Form_Element_Hidden('hiddenElement1');
        $this->addElement($element);

    }

    public function loadDefaultDecorators()
    {
        foreach ($this->getElements() as $element) {
            if ($element->getType() === "Zend_Form_Element_Hidden") {
                $element->setDecorators($this->_hiddenElementDecorator);
            }
        }

        // Add a decorator prefix path pointing to our new nifty decorator.
        $this->addElementPrefixPath('My_Form_Decorator', '/path/to/Decorator', Zend_Form_Element::DECORATOR);
        parent::loadDefaultDecorators();
    }
}

Easy as pie, no?

chuckg
You, sir, are a gentleman! I salute you, and make a toast to your honour!
lo_fye
D'oh. It's not working for me :( $this->getElements() is returning an empty array :-| There are definitely elements in the form, though!
lo_fye