Magento 2.1.2 Ui Component formElement seleccionar de múltiples menús desplegables

10

Tengo dos menús desplegables, uno para Horas y otro para Minutos . He logrado mostrar el menú desplegable durante horasingrese la descripción de la imagen aquí

Pero cualquiera podría ayudar: ¿cómo puedo mostrar un menú desplegable durante minutos, junto a las horas en el formulario Componente Ui? como el de la imageningrese la descripción de la imagen aquí

<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>

Mi modelo devuelve los valores de horas

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
fuente

Respuestas:

3

Aquí hay una manera de hacerlo creando un componente de interfaz de usuario personalizado. Requiere que el campo de respaldo sea un varchar.

Defina el componente ui en 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;
        })()
    });
});

y la plantilla, en 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}"/>

Úselo en su formulario xml de esta manera:

<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>

El valor de los dos menús desplegables se fusiona para producir una cadena como '0130'para representar el tiempo 1:30, por lo que su tipo de datos debe ser varchar; de lo contrario, se eliminará el '0' inicial.

Aaron Allen
fuente
Seguí lo que dijiste y funciona como un milagro :)
Verdu
¿Cómo usar xml para artículos sí / no?
jafar pinjar
0

Utilizo un elemento de formulario personalizado para lograrlo.

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);
    }
}

Personalícelo para que se ajuste a sus requisitos, por ejemplo, eliminando el segundo campo.

Cómo utilizar:

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
fuente
Gracias @Rendy Eko Prastiyo, lo hiciste usando bloques. Estoy implementando a través de Ui Components.
Verdu
No creo que sea posible. Incluso el Catálogo de Magento utiliza un modificador de formulario para lograr el modo en línea weighty las product_has_weightcolumnas en el backend de edición del producto. Ver Magento\Catalog\Ui\DataProvider\Product\Form\Modifier::customizeWeightField.
Rendy Eko Prastiyo
Bien ! Parece que deberíamos lograrlo a través del bloque; como lo hiciste! Hubiera sido mucho mejor si pudiéramos usar el selector de tiempo, que se menciona en los documentos de magento 2, pero la implementación no está disponible devdocs.magento.com/guides/v2.0/pattern-library/…
Verdu