Magento 2.1.2 Ui- Component formElement sélectionner parmi plusieurs listes déroulantes

10

J'ai deux listes déroulantes une pour les heures et une pour les minutes. J'ai réussi à afficher la liste déroulante pendant des heuresentrez la description de l'image ici

Mais n'importe qui pourrait m'aider - comment afficher une liste déroulante pour les minutes, à côté des heures sous la forme du composant Ui? comme celui de l'image.entrez la description de l'image ici

<field name="start_date">
    <argument name="data" xsi:type="array">
        <item name="options" xsi:type="object">NameSpace\ModuleName\Model\Xyz\Source\Hours</item>                
        <item name="config" xsi:type="array">
            <item name="label" xsi:type="string" translate="true">Monday Opening Time</item>
            <item name="visible" xsi:type="boolean">true</item>
            <item name="dataType" xsi:type="string">number</item>
            <item name="formElement" xsi:type="string">select</item>
            <item name="source" xsi:type="string">item</item>
            <item name="dataScope" xsi:type="string">start_date</item>
            <item name="sortOrder" xsi:type="number">220</item>
            <item name="validation" xsi:type="array">
                <item name="required-entry" xsi:type="boolean">true</item>
            </item>
        </item>
    </argument>      
</field>

Mon modèle renvoie les valeurs des heures

public function getHours()
{
    $availableOptions = [
        '0' => '00',
        '1' => '01',
        '2' => '02',
        '3' => '03',
        '4' => '04',
        '5' => '05',
        '6' => '06',
        '7' => '07',
        '8' => '08',
        '9' => '09',
        '10' => '10',
        '11' => '11',
        '12' => '12',
        '13' => '13',
        '14' => '14',
        '15' => '15',
        '16' => '16',
        '17' => '17',
        '18' => '18',
        '19' => '19',
        '20' => '20',
        '21' => '21',
        '22' => '22',
        '23' => '23',
    ];
    return $availableOptions;
}
Verdu
la source

Réponses:

3

Voici un moyen de le faire en créant un composant d'interface utilisateur personnalisé. Il nécessite que le champ de support soit un varchar.

Définissez le composant ui dans Your_Module/view/base/web/js/form/element/time.js:

define([
    'Magento_Ui/js/form/element/abstract'
], function (AbstractElement) {
    'use strict';

    return AbstractElement.extend({
        defaults: {
            elementTmpl: 'Your_Module/form/time'
        },

        initialize: function () {
            this._super();

            this.hours = '00';
            this.minutes = '00';

            this.observe(['hours', 'minutes']);

            var value = this.value();

            this.hours(value.slice(0,2));
            this.minutes(value.slice(2));
        },

        userChanges: function () {
            this._super();

            this.value(this.hours() + this.minutes());
        },

        hoursOpts: (function () {
            var opts = [];

            for (var i=0; i<24; i++) {
                opts.push({
                    label: i.toString(),
                    value: ('0' + i).slice(-2)
                })
            }

            return opts;
        })(),

        minutesOpts: (function () {
            var opts = [];

            for (var i=0; i<60; i++) {
                opts.push({
                    label: ('0' + i).slice(-2),
                    value: ('0' + i).slice(-2)
                })
            }

            return opts;
        })()
    });
});

et le modèle, dans Your_Module/view/base/web/template/form/time.html:

<select class="admin__control-select"
        data-bind="
        optgroup: hoursOpts,
        optionsValue: 'value',
        optionsText: 'label',
        value: hours,
        event: {change: userChanges}"/>

<select class="admin__control-select"
        data-bind="
        optgroup: minutesOpts,
        optionsValue: 'value',
        optionsText: 'label',
        value: minutes,
        event: {change: userChanges}"/>

Utilisez-le dans votre formulaire xml comme ceci:

<field name="start_date">
        <argument name="data" xsi:type="array">
             <item name="config" xsi:type="array">
                <item name="label" xsi:type="string" translate="true">Monday Opening Time</item>
                <item name="component" xsi:type="string">Your_Module/js/form/element/time</item>
                <item name="visible" xsi:type="boolean">true</item>
                <item name="dataType" xsi:type="string">text</item>
                <item name="formElement" xsi:type="string">input</item>
                <item name="source" xsi:type="string">item</item>
                <item name="dataScope" xsi:type="string">start_date</item>
                <item name="sortOrder" xsi:type="number">220</item>
                <item name="validation" xsi:type="array">
                <item name="required-entry" xsi:type="boolean">true</item>
            </item>
          </item>
        </argument>      
    </field>

La valeur des deux listes déroulantes est fusionnée pour produire une chaîne comme '0130'pour représenter l'heure 1:30, donc votre type de données doit être varchar sinon le `` 0 '' principal sera supprimé.

Aaron Allen
la source
J'ai suivi ce que vous avez dit et fonctionne comme un miracle :)
Verdu
comment utiliser xml pour les éléments oui / non?
jafar pinjar
0

J'utilise un élément de formulaire personnalisé pour y parvenir.

namespace VendorName\ModuleName\Block\Widget\Form\Element;

use Magento\Framework\Data\Form\Element\AbstractElement;
use Magento\Framework\Data\Form\Element\Factory as ElementFactory;
use Magento\Framework\Data\Form\Element\CollectionFactory;
use Magento\Framework\Escaper;

/**
 * Class Time.
 */
class Time extends AbstractElement
{
    /**
     * Constructor.
     *
     * @param ElementFactory    $elementFactory
     * @param CollectionFactory $collectionFactory
     * @param Escaper           $escaper
     * @param array             $data
     */
    public function __construct(
        ElementFactory $elementFactory,
        CollectionFactory $collectionFactory,
        Escaper $escaper,
        array $data = []
    ) {
        parent::__construct($elementFactory, $collectionFactory, $escaper, $data);

        $this->setType('time');
    }

    /**
     * {@inheritdoc}
     */
    public function getElementHtml()
    {
        $this->addClass('select admin__control-select');

        $defaultValues = [
            'time'   => '00:00:00',
            'hour'   => '00',
            'minute' => '00',
            'second' => '00',
        ];

        $values = $this->getValue();
        if (!$values) {
            $values = $defaultValues;
        } else {
            $time = explode(':', $values);
            $values = [
                'time'   => $values,
                'hour'   => $time[0],
                'minute' => $time[1],
                'second' => $time[2],
            ];
        }

        // value container element
        $html = '<input type="hidden" id="' . $this->getHtmlId() . '" name="' . $this->getName()
            . '" value="' . $values['time'] . '" '. $this->_getUiId() . '/>' . PHP_EOL
        ;

        // hours control
        $html .= '<select style="width:80px" id="' . $this->getHourControlHtmlId() . '" '
            . $this->serialize($this->getControlHtmlAttributes()) . ' title="' . __('hours') . '" '
            . $this->_getUiId('hour') . '>' . PHP_EOL
        ;
        for ($i = 0; $i < 24; $i++) {
            $hour = str_pad($i, 2, '0', STR_PAD_LEFT);
            $html .= '<option'
                . ' value="' . $hour . '"'
                . ($values['hour'] == $i ? ' selected="selected"' : '') . '>'
                . $hour
                . '</option>' . PHP_EOL
            ;
        }
        $html .= '</select>' . PHP_EOL;

        // minutes control
        $html .= ':&nbsp;<select style="width:80px" id="' . $this->getMinuteControlHtmlId() . '" '
            . $this->serialize($this->getControlHtmlAttributes()) . ' title="' . __('minutes') . '" '
            . $this->_getUiId('minute') . '>' . PHP_EOL
        ;
        for ($i = 0; $i < 60; $i++) {
            $minute = str_pad($i, 2, '0', STR_PAD_LEFT);
            $html .= '<option'
                . ' value="' . $minute . '"'
                . ($values['minute'] == $i ? ' selected="selected"' : '') . '>'
                . $minute
                . '</option>' . PHP_EOL
            ;
        }
        $html .= '</select>' . PHP_EOL;

        // seconds control
        $html .= ':&nbsp;<select style="width:80px" id="' . $this->getSecondControlHtmlId() . '" '
            . $this->serialize($this->getControlHtmlAttributes()) . ' title="' . __('seconds') . '" '
            . $this->_getUiId('second') . '>' . PHP_EOL
        ;
        for ($i = 0; $i < 60; $i++) {
            $second = str_pad($i, 2, '0', STR_PAD_LEFT);
            $html .= '<option'
                . ' value="' . $second . '"'
                . ($values['hour'] == $i ? ' selected="selected"' : '') . '>'
                . $second
                . '</option>' . PHP_EOL
            ;
        }
        $html .= '</select>' . PHP_EOL;

        $html .= $this->getAfterElementHtml();

        $html .= $this->getAfterElementJs();

        return $html;
    }

    /**
     * Get after element JS.
     *
     * @return string
     */
    public function getAfterElementJs()
    {
        $js = '
            <script type="text/javascript">
                require(["jquery"], function ($) {
                    var onTimeContainerChange = function () {
                        var time      = $("#' . $this->getHtmlId() . '").val();
                        var timeArray = time.split(":");

                        $("#' . $this->getHourControlHtmlId() . '").val(timeArray[0]);
                        $("#' . $this->getMinuteControlHtmlId() . '").val(timeArray[1]);
                        $("#' . $this->getSecondControlHtmlId() . '").val(timeArray[2]);
                    };
                    $(document).ready(onTimeContainerChange);
                    $("#' . $this->getHtmlId() . '").change(onTimeContainerChange);

                    var onTimeControlChange = function () {
                        var time = $("#' . $this->getHourControlHtmlId() . '").val()
                            + ":" + $("#' . $this->getMinuteControlHtmlId() . '").val()
                            + ":" + $("#' . $this->getSecondControlHtmlId() . '").val()
                        ;

                        $("#' . $this->getHtmlId() . '").val(time);
                    }
                    $("'
                        . '#' . $this->getHourControlHtmlId() . ','
                        . '#' . $this->getMinuteControlHtmlId() . ','
                        . '#' . $this->getSecondControlHtmlId()
                    . '").change(onTimeControlChange);
                });
            </script>
        ';

        return $js;
    }

    /**
     * Get hour control html id prefix.
     *
     * @return string
     */
    protected function getHourControlHtmlId()
    {
        return $this->getHtmlId() . '_hour_control';
    }

    /**
     * Get minute control html id prefix.
     *
     * @return string
     */
    protected function getMinuteControlHtmlId()
    {
        return $this->getHtmlId() . '_minute_control';
    }

    /**
     * Get second control html id prefix.
     *
     * @return string
     */
    protected function getSecondControlHtmlId()
    {
        return $this->getHtmlId() . '_second_control';
    }

    /**
     * Get control html attributes.
     *
     * @return array
     */
    protected function getControlHtmlAttributes()
    {
        $propertiesToClear = ['title'];
        $htmlAttributes    = $this->getHtmlAttributes();

        return array_diff($htmlAttributes, $propertiesToClear);
    }
}

Personnalisez-le en fonction de vos besoins, par exemple en supprimant le deuxième champ.

Comment utiliser:

use VendorName\ModuleName\Block\Widget\Form\Element\Time as TimeElement;

$form->addType('custom_time', TimeElement::class);
$form->addField(
    '[id_of_your_field]',
    'custom_time',
    [
        ... // data
    ]
);
Rendy Eko Prastiyo
la source
Merci @Rendy Eko Prastiyo, vous avez fait cela en utilisant des blocs - je l'implémente via Ui Components.
Verdu
Je ne pense pas que ce soit possible. Même le catalogue Magento utilise le modificateur de formulaire pour obtenir le mode en ligne weightet les product_has_weightcolonnes sur le backend de modification du produit. Tu vois Magento\Catalog\Ui\DataProvider\Product\Form\Modifier::customizeWeightField.
Rendy Eko Prastiyo
Bien ! Il semble que nous devrions y parvenir via un bloc; comme tu l'as fait! Cela aurait été bien mieux si nous avions pu utiliser le sélecteur de temps, qui est mentionné dans les documents magento 2, mais l'implémentation n'est pas disponible devdocs.magento.com/guides/v2.0/pattern-library/…
Verdu