zend-framework2zend-form2

ZF2 FormInput to show error class on validation fail


My form has multiple elements being rendered in the format:

<div class="form-group">
    <?php echo $this->formlabel($form->get('lastname')); ?>
    <?php echo $this->forminput($form->get('lastname')); ?>
    <?php echo $this->formElementErrors($form->get('lastname')); ?>
</div>

I do this so I can have my element next to my label as opposed to inside it:

<label for="lastname">Lastname</label><input .../>
<ul><li>error messages</li></ul>

What I have noticed is that on validation fail the input is not getting the input-error class. When I change the above code to <?php echo $this->formrow($form->get('lastname')); ?> the input is put into the label (which I don't want) and the input gets the error class as expected:

<label>Lastname<input ... class="input-error"/></label>

How do I get the input-error class into the element via $this->forminput?

When I do formrow before forminput then the input in both has the error class, but when I do forminput on it's own it does not.

[edit]

Short term I have put formrow (without the echo) above my existing code and now my input field is showing the error class, but that feels like a bit of a hack, and I would have to do that for each element in my app that I have set up like this.


Solution

  • I have created a view helper to add the missing class to forminput:

    <?php
    /**
     * Extend zend form view helper forminput to add error class to element on validation
     * fail
     * 
     * @package    RPK
     * @author     Richard Parnaby-King
     */
    namespace RPK\Form\View\Helper;
    use Zend\Form\View\Helper\FormInput as ZendFormInput;
    
    class FormInput extends ZendFormInput
    {
        protected $inputErrorClass = 'input-error';
    
        /**
         * Render a form <input> element from the provided $element
         *
         * @param  ElementInterface $element
         * @throws Exception\DomainException
         * @return string
         */
        public function render(\Zend\Form\ElementInterface $element)
        {
            $inputErrorClass = $this->inputErrorClass;
    
            // Following code block copied from \Zend\Form\View\Helper\FormRow
            // Does this element have errors ?
            if (count($element->getMessages()) > 0 && !empty($inputErrorClass)) {
                $classAttributes = ($element->hasAttribute('class') ? $element->getAttribute('class') . ' ' : '');
                $classAttributes = $classAttributes . $inputErrorClass;
    
                $element->setAttribute('class', $classAttributes);
            }
            return parent::render($element);
        }
    }
    

    I then tell my application to use this view helper in my Module.php file:

    public function onBootstrap(MvcEvent $e) {
        $services = $e->getApplication()->getServiceManager();
        //add custom forminput viewhelper
        $services->get('ViewHelperManager')->setFactory('forminput', function (\Zend\View\HelperPluginManager $manager) {
            return new \RPK\Form\View\Helper\FormInput();
        });
    }