Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

zend form custom attribute in select option?

I want know how to add custom attribute for option in a select field of Zend form.

PHP:

$option_values = array("multiOptions" => array(
    "US" => "United States",
    "CA" => "Canada",
));

$type=array('big','small');
$option= new Zend_Form_Element_Select('option',  $option_values);

HTML:

<select>
    <option value='US' type='big'>United States</option>
    <option value='CA' type='small'>Canada</option>
</select>

How to add this type attribute in the option?

like image 848
Karthik Avatar asked Mar 23 '11 06:03

Karthik


3 Answers

It is not possible using ZF's implementation of Zend_Form_Element_Select. You need to create your own element. I have done something similar, here's the relevant code:

<?php
require_once 'Zend/Form/Element/Select.php';

/**
 * Select, but with the possibility to add attributes to <option>s
 * @author Dominik Marczuk
 */
class Zend_Form_Element_SelectAttribs extends Zend_Form_Element {

    public $options = array();

    public $helper = 'selectAttribs';

    /**
     * Adds a new <option>
     * @param string $value value (key) used internally
     * @param string $label label that is shown to the user
     * @param array $attribs additional attributes
     */
    public function addOption ($value,$label = '',$attribs = array()) {
        $value = (string) $value;
        if (!empty($label)) $label = (string) $label;
        else $label = $value;
        $this->options[$value] = array(
            'value' => $value,
            'label' => $label
        ) + $attribs;
        return $this;
    }
}

Put this into /library/Zend/Form/Element/SelectAttribs.php. You also need a helper to render the element. Put it into your view helpers directory, name it SelectAttribs.php as well. Here's the contents of my file:

<?php
require_once 'Zend/View/Helper/FormElement.php';

class Zend_View_Helper_SelectAttribs extends Zend_View_Helper_FormElement {
    public function selectAttribs($name, $value = null, $attribs = null, $options = null, $listsep = "<br />\n") {
        $info = $this->_getInfo($name, $value, $attribs, $options, $listsep);
        extract($info); // name, id, value, attribs, options, listsep, disable

        // force $value to array so we can compare multiple values to multiple
        // options; also ensure it's a string for comparison purposes.
        $value = array_map('strval', (array) $value);

        // now start building the XHTML.
        $disabled = '';
        if (true === $disable) {
            $disabled = ' disabled="disabled"';
        }

        // Build the surrounding select element first.
        $xhtml = '<select'
                . ' name="' . $this->view->escape($name) . '"'
                . ' id="' . $this->view->escape($id) . '"'
                . $disabled
                . $this->_htmlAttribs($attribs)
                . ">\n  ";

        // build the list of options
        $list = array();
        $translator = $this->getTranslator();
        foreach ($options as $opt_value => $option) {
            $opt_disable = '';
            if (is_array($disable) && in_array($opt_value, $disable)) {
                $opt_disable = ' disabled="disabled"';
            }
            $list[] = $this->_build($option, $disabled);
        }

        // add the options to the xhtml and close the select
        $xhtml .= implode("\n   ", $list) . "\n</select>";

        return $xhtml;
    }

    protected function _build($option, $disabled) {
        $html = '<option';
        foreach ($option as $attrib => $value) {
            $html .= " $attrib=\"$value\"";
        }
        return $html.$disabled.">".$option['label']."</option>";
    }
}

With this, you should be ready to go:

$elt = new Zend_Form_Element_SelectAttribs('whatever');
$elt->addOption($value,$label,array('attribname' => 'attribvalue'));
like image 200
mingos Avatar answered Oct 21 '22 10:10

mingos


Using addMultiOption($value,$label) I just set the value parameter to something like:

$value = $id . '" ref="' . $ref;

and when it renders you get:

<option value="<idValue>" ref="<refValue"><labelValue></option>

Hope this helps....

Okay, value gets escaped but optionClasses does not so inside the loop that adds the addMultiOptions(val,lable) I do something like this:

$optionClasses[<val>] = 'ref_' . <val> . '" ref="' . <ref>;

and then after the loop just do a setAttrib('optionClasses',$optionClasses)

And that actually works...

I answered this for another question but could not find a way to add a comment here to reference it; It was Zend Framework addMultiOption adding custom parameters like "rel" for options

like image 4
StevenHill Avatar answered Oct 21 '22 12:10

StevenHill


I didn't find @mingos's answer complete and had some issues with implementing setting the value. His answer helped a lot with what needed to be extended and changed however. Once I had that start the rest was pretty easy. I just extended ZF1's Select and overrode where I needed:

/**
 * Select, now with abbility to specify attributes on <Option>, addMultiOption has new syntax
 * @author Seth Miller
 */
class MyNamespace_Form_Element_SelectAttribs extends Zend_Form_Element_Select {

    public $options = array();
    public $helper = 'selectAttribs';

    /**
     * Add an option
     *
     * @param  string $option
     * @param  string $value
     * @return Zend_Form_Element_Multi
     */
    public function addMultiOption($value, $label = '', $attribs = array()) {
        $value = (string) $value;
        if (!empty($label)) {
            $label = (string) $label;
        }
        else {
            $label = $value;
        }

        $this->_getMultiOptions();
        if (!$this->_translateOption($value, $label)) {
            $this->options[$value] = array(
                'value'  => $value,
                'label'  => $label
                    ) + $attribs;
        }
        return $this;
    }

    /**
     * Add many options at once
     *
     * @param  array $options
     * @return Zend_Form_Element_Multi
     */
    public function addMultiOptions(array $options) {
        foreach ($options as $optionKey => $optionProperties) {
            if (is_array($optionProperties)
                    && array_key_exists('key', $optionProperties)
                    && array_key_exists('value', $optionProperties)
            ) {
                if(array_key_exists('key', $optionProperties)) $optionKey = $optionProperties['key'];
                $this->addMultiOption($optionKey, $optionProperties['value'], $optionProperties['attribs']);
            }
            else {
                $this->addMultiOption($optionKey, $optionProperties);
            }
        }
        return $this;
    }

    public function isValid($value, $context = null)
    {
        if ($this->registerInArrayValidator()) {
            if (!$this->getValidator('InArray')) {
                $multiOptions = $this->getMultiOptions();
                $options      = array();

                foreach ($multiOptions as $optionKey => $optionData) {
                    // optgroup instead of option label
                    if (is_array($optionData['options'])) {
                        $options = array_merge($options, array_keys($optionData['options']));
                    }
                    else {
                        $options[] = $optionKey;
                    }
                }

                $this->addValidator(
                    'InArray',
                    true,
                    array($options)
                );
            }
        }
        return parent::isValid($value, $context);
    }
}

And the view helper:

class MyNamespace_View_Helper_SelectAttribs extends Zend_View_Helper_FormElement {

public function selectAttribs($name, $value = null, $attribs = null, $options = null, $listsep = "<br />\n") {
    $info = $this->_getInfo($name, $value, $attribs, $options, $listsep);
    extract($info); // name, id, value, attribs, options, listsep, disable
    // force $value to array so we can compare multiple values to multiple
    // options; also ensure it's a string for comparison purposes.
    $value = array_map('strval', (array) $value);

    // check if element may have multiple values
    $multiple = '';

    if (substr($name, -2) == '[]') {
        // multiple implied by the name
        $multiple = ' multiple="multiple"';
    }

    if (isset($attribs['multiple'])) {
        // Attribute set
        if ($attribs['multiple']) {
            // True attribute; set multiple attribute
            $multiple = ' multiple="multiple"';

            // Make sure name indicates multiple values are allowed
            if (!empty($multiple) && (substr($name, -2) != '[]')) {
                $name .= '[]';
            }
        }
        else {
            // False attribute; ensure attribute not set
            $multiple = '';
        }
        unset($attribs['multiple']);
    }

    // now start building the XHTML.
    $disabled = '';
    if (true === $disable) {
        $disabled = ' disabled="disabled"';
    }

    // Build the surrounding select element first.
    $xhtml = '<select'
            .' name="'.$this->view->escape($name).'"'
            .' id="'.$this->view->escape($id).'"'
            .$multiple
            .$disabled
            .$this->_htmlAttribs($attribs)
            .">\n    ";

    // build the list of options
    $list = array();
    $translator = $this->getTranslator();
    foreach ((array) $options as $optionKey => $optionData) {
        if (isset($optionData['options'])) {
            $optDisable = '';
            if (is_array($disable) && in_array($optionData['value'], $disable)) {
                $optDisable = ' disabled="disabled"';
            }
            if (null !== $translator) {
                $optValue    = $translator->translate($optionData['value']);
            }
            $optId       = ' id="'.$this->view->escape($id).'-optgroup-'
                    .$this->view->escape($optionData['value']).'"';
            $list[]      = '<optgroup'
                    .$optDisable
                    .$optId
                    .' label="'.$this->view->escape($optionData['value']).'">';
            foreach ($optionData['options'] as $optionKey2 => $optionData2) {
                $list[]  = $this->_build($optionKey2, $optionData2, $value, $disable);
            }
            $list[]  = '</optgroup>';
        }
        else {
            $list[] = $this->_build($optionKey, $optionData, $value, $disable);
        }
    }

    // add the options to the xhtml and close the select
    $xhtml .= implode("\n    ", $list)."\n</select>";

    return $xhtml;
}

/**
 * Builds the actual <option> tag
 *
 * @param string $value Options Value
 * @param string $label Options Label
 * @param array  $selected The option value(s) to mark as 'selected'
 * @param array|bool $disable Whether the select is disabled, or individual options are
 * @return string Option Tag XHTML
 */
protected function _build($optionKey, $optionData, $selected, $disable)
{
    if (is_bool($disable)) {
        $disable = array();
    }

    $opt = '<option';

    foreach ($optionData as $attrib => $attribValue) {
        $opt .= ' '.$this->view->escape($attrib).'="'.$this->view->escape($attribValue).'"';
    }

    // selected?
    if (in_array((string) $optionData['value'], $selected)) {
        $opt .= ' selected="selected"';
    }

    // disabled?
    if (in_array($optionData['value'], $disable)) {
        $opt .= ' disabled="disabled"';
    }

    $opt .= '>' . $this->view->escape($optionData['label']) . "</option>";

    return $opt;
}

}

And implementation in a form would be something like:

$selectElement = new MyNamespace_Form_Element_SelectAttribs('selectElementName');
$selectElement->addMultiOption($value, $label, array('data-custom' => 'custom data embedded in option tag.');

I hope that helps someone. Thanks.

like image 2
four43 Avatar answered Oct 21 '22 11:10

four43