skip to Main Content

Need time picker at ui form and ui grid inline editor magento 2.3.3

3

Answers


  1. I faced the same issue and I found out that the same issue was reported in the Magento 2 Github repository:

    https://github.com/magento/magento2/issues/23157

    And this is the Pull Request with the solution:

    https://github.com/magento/magento2/pull/31549

    It’s fixed in Magento 2.4.
    So, i made a patch from that Pull Request to apply in previous Magento 2 versions with composer patches:

    From: Santiago Valveson <https://www.linkedin.com/in/santiago-valveson/>
    Subject: [PATCH] Invalid date when timeOnly defined on datetime UIComponent -
     Fixed in the v2.4
    
    ---
     view/base/web/js/form/element/date.js         |  9 +++-
     .../js/lib/knockout/bindings/datepicker.js    | 47 +++++++++----------
     2 files changed, 30 insertions(+), 26 deletions(-)
    
    diff --git a/view/base/web/js/form/element/date.js b/view/base/web/js/form/element/date.js
    index 22fcdcb..a5447b2 100644
    --- a/view/base/web/js/form/element/date.js
    +++ b/view/base/web/js/form/element/date.js
    @@ -107,6 +107,13 @@ define([
                 return this._super().observe(['shiftedValue']);
             },
    
    +        /**
    +         * @inheritdoc
    +         */
    +        getPreview: function () {
    +            return this.shiftedValue();
    +        },
    +
             /**
              * Prepares and sets date/time value that will be displayed
              * in the input field.
    @@ -120,7 +127,7 @@ define([
                     if (this.options.showsTime && !this.options.timeOnly) {
                         shiftedValue = moment.tz(value, 'UTC').tz(this.storeTimeZone);
                     } else {
    -                    shiftedValue = moment(value, this.outputDateFormat);
    +                    shiftedValue = moment(value, this.outputDateFormat, true);
                     }
    
                     if (!shiftedValue.isValid()) {
    diff --git a/view/base/web/js/lib/knockout/bindings/datepicker.js b/view/base/web/js/lib/knockout/bindings/datepicker.js
    index 2fab8c2..ff09835 100644
    --- a/view/base/web/js/lib/knockout/bindings/datepicker.js
    +++ b/view/base/web/js/lib/knockout/bindings/datepicker.js
    @@ -7,11 +7,8 @@ define([
         'ko',
         'underscore',
         'jquery',
    -    'mage/translate',
    -    'mage/calendar',
    -    'moment',
    -    'mageUtils'
    -], function (ko, _, $, $t, calendar, moment, utils) {
    +    'mage/translate'
    +], function (ko, _, $, $t) {
         'use strict';
    
         var defaults = {
    @@ -46,10 +43,12 @@ define([
                     observable = config;
                 }
    
    -            $(el).calendar(options);
    +            require(['mage/calendar'], function () {
    +                $(el).calendar(options);
    
    -            ko.utils.registerEventHandler(el, 'change', function () {
    -                observable(this.value);
    +                ko.utils.registerEventHandler(el, 'change', function () {
    +                    observable(this.value);
    +                });
                 });
             },
    
    @@ -62,6 +61,7 @@ define([
              */
             update: function (element, valueAccessor) {
                 var config = valueAccessor(),
    +                $element = $(element),
                     observable,
                     options = {},
                     newVal;
    @@ -75,26 +75,23 @@ define([
                     observable = config;
                 }
    
    -            if (_.isEmpty(observable())) {
    -                if ($(element).datepicker('getDate')) {
    -                    $(element).datepicker('setDate', null);
    -                    $(element).blur();
    +            require(['moment', 'mage/utils/misc', 'mage/calendar'], function (moment, utils) {
    +                if (_.isEmpty(observable())) {
    +                    newVal = null;
    +                } else {
    +                    newVal = moment(
    +                        observable(),
    +                        utils.convertToMomentFormat(
    +                            options.dateFormat + (options.showsTime ? ' ' + options.timeFormat : '')
    +                        )
    +                    ).toDate();
                     }
    -            } else {
    -                newVal = moment(
    -                    observable(),
    -                    utils.convertToMomentFormat(
    -                        options.dateFormat + (options.showsTime ? ' ' + options.timeFormat : '')
    -                    )
    -                ).toDate();
    
    -                if ($(element).datepicker('getDate') == null ||
    -                    newVal.valueOf() !== $(element).datepicker('getDate').valueOf()
    -                ) {
    -                    $(element).datepicker('setDate', newVal);
    -                    $(element).blur();
    +                if (!options.timeOnly) {
    +                    $element.datepicker('setDate', newVal);
    +                    $element.blur();
                     }
    -            }
    +            });
             }
         };
     });
    --
    2.21.0
    

    This is the Magento 2 guide to apply composer patches:

    https://devdocs.magento.com/guides/v2.3/comp-mgr/patching/composer.html

    This is the code to make it work well (taken from the QA done by Magento to approve the Pull Request
    ):

    <field name="start_date">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="dataType" xsi:type="string">string</item>
                        <item name="label" xsi:type="string" translate="true">Start Time</item>
                        <item name="formElement" xsi:type="string">date</item>
                        <item name="source" xsi:type="string">import_profile</item>
                        <item name="dataScope" xsi:type="string">start_time</item>
                        <item name="options" xsi:type="array">
                        <item name="timeOnlyTitle" xsi:type="string">Select Start Time</item>
                        <item name="showsTime" xsi:type="boolean">true</item>
                        <item name="timeOnly" xsi:type="boolean">true</item>
                        <item name="timeFormat" xsi:type="string">HH:mm:ss</item>
                        <item name="dateFormat" xsi:type="string">yyyy-MM-dd</item>
                        </item>
                    </item>
                </argument>
            </field>
    



    Another solution (better to me) is use the type time input:

    https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/time

    And create a new input template (I choose this way because i couldn’t receive the time post param of the original date UI field.

    in your module:
    Vendor/ModuleName/view/adminhtml/web/template/form/element/time_input.html

    <input class="admin__control-text" type="time"
           data-bind="
            event: {change: userChanges},
            value: value,
            hasFocus: focused,
            valueUpdate: valueUpdate,
            attr: {
                name: inputName,
                placeholder: placeholder,
                'aria-describedby': noticeId,
                id: uid,
                disabled: disabled,
        }"/>
    

    And then, in your form:

        <field name="start_date" formElement="input">
            <settings>
                <elementTmpl>Vendor_ModuleName/form/element/time_input</elementTmpl>
                <dataType>text</dataType>
                <dataScope>start_date</dataScope>
                <label translate="true">Start Date</label>
                <validation>
                    <rule name="required-entry" xsi:type="boolean">true</rule>
                </validation>
            </settings>
        </field>
    

    And you can standardize the post param in the Save/Validator Controller and the Data Provider with this:

    date('H:i', strtotime($this->_request->getParam('opening_time')))
    

    Should looks like this:

    Input image

    Input image with time select

    Login or Signup to reply.
  2. You can create DatetimePicker class in yor module

    class DatePicker extends MagentoConfigBlockSystemConfigFormField
    {
    /**
    * @var MagentoFrameworkRegistry
    */
    protected $_registry;

    /**
     * @param MagentoBackendBlockTemplateContext  $context
     * @param MagentoFrameworkRegistry $coreRegistry
     * @param array    $data
     */
    public function __construct(
        MagentoBackendBlockTemplateContext $context,
        MagentoFrameworkRegistry $registry,
        array $data = []
    ) {
        $this->_registry = $registry;
        parent::__construct($context, $data);
    }
    
    /**
     * @param MagentoFrameworkDataFormElementAbstractElement $element
     * @return string
     */
    protected function _getElementHtml(MagentoFrameworkDataFormElementAbstractElement $element)
    {
        $html = $element->getElementHtml();
    
        if (!$this->_registry->registry('datepicker_loaded')) {
            $this->_registry->registry('datepicker_loaded', 1);
        }
    
        $html .= '<button type="button" style="display:none;" class="ui-datepicker-trigger '
            .'v-middle"><span>Select Date</span></button>';
    
        $html .= '<script type="text/javascript">
            require(["jquery", "jquery/ui"], function (jq) {
                jq(document).ready(function () {
                    jq("#' . $element->getHtmlId() . '").datepicker( { dateFormat: "yy/mm/dd" } );
                    jq(".ui-datepicker-trigger").removeAttr("style");
                    jq(".ui-datepicker-trigger").click(function(){
                        jq("#' . $element->getHtmlId() . '").focus();
                    });
                });
            });
            </script>';
    
        return $html;
    }
    

    }

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search