【问题标题】:Use Nette form with material design在材料设计中使用 Nette 形式
【发布时间】:2023-03-05 09:44:01
【问题描述】:

我最近购买了 angular 主题 admin.io (https://themeforest.net/item/adminio-responsive-material-design-admin/10761963),我想将它与 PHP Nette 框架一起使用。通过手动渲染,文本输入和按钮一切顺利。但我被选择元素卡住了。 它应该是这样的:

<md-select ng-model="someVal" name="priority" placeholder="Zvolte prioritu">
     <md-option value="1">Urgent</md-option>
     <md-option value="2">Vysoká</md-option>
     <md-option value="3">Střední</md-option>
     <md-option value="4">Nízká</md-option>
</md-select>

但 Nette 将其呈现为基本 &lt;select&gt;。我可以使用&lt;md-select n:name=""&gt; 渲染选择,但是渲染选项存在问题。有什么方法可以手动渲染&lt;option&gt;,就像我对选择和整个表单所做的那样,或者我可以为该表单使用我自己的模板,或者请有人知道如何使它工作?谢谢!

【问题讨论】:

    标签: angularjs material-design nette


    【解决方案1】:

    这会有点困难。 Nette SelectBox 不是为此而构建的。您需要构建自己的控件。您可以使用Nette\Forms\Controls\SelectBox 作为模板并进行一些调整:

    <?php
    
    namespace App\Forms;
    
    use Nette;
    
    
    /**
     * Select box control that allows single item selection.
     */
    class MdSelectBox extends Nette\Forms\Controls\ChoiceControl
    {
        /** validation rule */
        const VALID = ':selectBoxValid';
    
        /** @var array of option / optgroup */
        private $options = [];
    
        /** @var mixed */
        private $prompt = false;
    
        /** @var array */
        private $optionAttributes = [];
    
    
        public function __construct($label = null, array $items = null)
        {
            parent::__construct($label, $items);
            $this->setOption('type', 'md-select');
            $this->addCondition(Nette\Forms\Form::BLANK)
                ->addRule([$this, 'isOk'], Nette\Forms\Validator::$messages[self::VALID]);
        }
    
    
        /**
         * Sets first prompt item in select box.
         * @param  string|object
         * @return static
         */
        public function setPrompt($prompt)
        {
            $this->prompt = $prompt;
            return $this;
        }
    
    
        /**
         * Returns first prompt item?
         * @return mixed
         */
        public function getPrompt()
        {
            return $this->prompt;
        }
    
    
        /**
         * Sets options and option groups from which to choose.
         * @return static
         */
        public function setItems(array $items, $useKeys = true)
        {
            if (!$useKeys) {
                $res = [];
                foreach ($items as $key => $value) {
                    unset($items[$key]);
                    if (is_array($value)) {
                        foreach ($value as $val) {
                            $res[$key][(string) $val] = $val;
                        }
                    } else {
                        $res[(string) $value] = $value;
                    }
                }
                $items = $res;
            }
            $this->options = $items;
            return parent::setItems(Nette\Utils\Arrays::flatten($items, true));
        }
    
    
        /**
         * Generates control's HTML element.
         * @return Nette\Utils\Html
         */
        public function getControl()
        {
            $items = $this->prompt === false ? [] : ['' => $this->translate($this->prompt)];
            foreach ($this->options as $key => $value) {
                $items[is_array($value) ? $this->translate($key) : $key] = $this->translate($value);
            }
    
            return Helpers::createSelectBox(
                $items,
                [
                    'disabled:' => is_array($this->disabled) ? $this->disabled : null,
                ] + $this->optionAttributes,
                $this->value
            )->addAttributes(parent::getControl()->attrs);
        }
    
    
        /**
         * @return static
         */
        public function addOptionAttributes(array $attributes)
        {
            $this->optionAttributes = $attributes + $this->optionAttributes;
            return $this;
        }
    
    
        /**
         * @return bool
         */
        public function isOk()
        {
            return $this->isDisabled()
                || $this->prompt !== false
                || $this->getValue() !== null
                || !$this->options
                || $this->control->size > 1;
        }
    }
    

    您还需要重写Nette\Forms\Helpers 类,这是使用Nette\Forms\Controls\SelectBox 无法实现此目的的主要原因:

    <?php
    
    namespace App\Forms;
    
    use Nette;
    use Nette\Utils\Html;
    
    
    /**
     * Forms helpers.
     */
    class Helpers
    {
        use Nette\StaticClass;
    
    
        /**
         * @return Html
         */
        public static function createSelectBox(array $items, array $optionAttrs = null, $selected = null)
        {
            if ($selected !== null) {
                $optionAttrs['selected?'] = $selected;
            }
            list($optionAttrs, $optionTag) = self::prepareAttrs($optionAttrs, 'md-option');
            $option = Html::el();
            $res = $tmp = '';
            foreach ($items as $group => $subitems) {
                if (is_array($subitems)) {
                    $res .= Html::el('md-optgroup')->label($group)->startTag();
                    $tmp = '</md-optgroup>';
                } else {
                    $subitems = [$group => $subitems];
                }
                foreach ($subitems as $value => $caption) {
                    $option->value = $value;
                    foreach ($optionAttrs as $k => $v) {
                        $option->attrs[$k] = isset($v[$value]) ? $v[$value] : null;
                    }
                    if ($caption instanceof Html) {
                        $caption = clone $caption;
                        $res .= $caption->setName('md-option')->addAttributes($option->attrs);
                    } else {
                        $res .= $optionTag . $option->attributes() . '>'
                            . htmlspecialchars((string) $caption, ENT_NOQUOTES, 'UTF-8')
                            . '</md-option>';
                    }
                    if ($selected === $value) {
                        unset($optionAttrs['selected'], $option->attrs['selected']);
                    }
                }
                $res .= $tmp;
                $tmp = '';
            }
            return Html::el('md-select')->setHtml($res);
        }
    
    
        private static function prepareAttrs($attrs, $name)
        {
            $dynamic = [];
            foreach ((array) $attrs as $k => $v) {
                $p = str_split($k, strlen($k) - 1);
                if ($p[1] === '?' || $p[1] === ':') {
                    unset($attrs[$k], $attrs[$p[0]]);
                    if ($p[1] === '?') {
                        $dynamic[$p[0]] = array_fill_keys((array) $v, true);
                    } elseif (is_array($v) && $v) {
                        $dynamic[$p[0]] = $v;
                    } else {
                        $attrs[$p[0]] = $v;
                    }
                }
            }
            return [$dynamic, '<' . $name . Html::el(null, $attrs)->attributes()];
        }
    }
    

    然后你可以像这样在你的表单中使用你新建的MdSelectBox

    $options = ['1' => 'Urgent', '2' => 'Medium', '3' => 'Low'];
    $form->addComponent(new \App\Forms\MdSelectBox('Priority', $options), 'priority');
    

    或者您可以在某处注册您的新控件以直接在表单上使用它作为addMdSelectBox()

    ObjectMixin::setExtensionMethod(Container::class, 'addMdSelectbox', function (Container $container, $name, $label = null, array $items = null) {
        return $container[$name] = new \App\Forms\MdSelectBox($label, $items);
    });
    

    【讨论】:

    • 抱歉回答晚了。我已经尝试过了,效果很好,但是 md-select 不会将其值发送到 onSuccess[] 函数。有什么方法可以发送它的值,否则我将不得不使用普通选择?
    • 当然可以,因为不是正常的选择。唯一的方法是,您在 JS 中使用 ajax 调用发送值。
    猜你喜欢
    • 2016-08-15
    • 1970-01-01
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    • 2019-12-25
    • 2015-02-05
    • 2015-04-17
    相关资源
    最近更新 更多