8

I want to show Timepicker in Ui Component Form. I could able to add the time field by using below code but not able to save value. Can anybody help on it.

   <field name="start_time">
        <argument name="data" xsi:type="array">                
            <item name="config" xsi:type="array">                    
                <item name="dataType" xsi:type="string">text</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">prmrule</item>
                <item name="dataScope" xsi:type="string">start_time</item>                    
                <item name="options" xsi:type="array">                             
                    <item name="controlType" xsi:type="string">select</item>
                    <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>                    
            </item>
        </argument>
    </field>

enter image description here

I am not getting that time which I have selected in ui_form. I am getting date in UTC format by default in Magento. I want to get only time which I have selected in ui_form.

Aasim Goriya
  • 5,444
  • 2
  • 28
  • 53
Dhairya Shah
  • 812
  • 6
  • 13

3 Answers3

4

You can try below code.

<field name="start_time">
    <argument name="data" xsi:type="array">                
        <item name="config" xsi:type="array">                    
            <item name="dataType" xsi:type="string">text</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">prmrule</item>
           <item name="dataScope" xsi:type="string">start_time</item>                                                
           <item name="options" xsi:type="array">                             
               <item name="controlType" xsi:type="string">select</item>
               <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="dateFormat" xsi:type="string">yyyy-MM-dd</item>
               <item name="timeFormat" xsi:type="string">h:mm a</item>            
           </item>                    
        </item>
    </argument>
</field>

In your Controller, use strtotime function.

public function execute()
{
   ----------------
   $data = $this->getRequest()->getPostValue();
   $dateTime = $data['start_time'];
   $start_time = date("H:i:s", strtotime($dateTime));
   ----------------
}
Pritam Biswas
  • 2,602
  • 1
  • 9
  • 11
3

You need to "create" your own UI Component.

You can do this by extending the Date UI Component.

#1 Add the XML to your form

In this example, the component that we will be creating is called time.

Note that you can declare a template in the following XML. However, it won't really do any good as it is the XHTML template that will wrap the Knockout template that does the actual rendering. There are other nodes you can declare here like validation.

<field name="time_field">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="label" xsi:type="string" translate="true">Time</item>
            <item name="dataType" xsi:type="string">text</item>
            <item name="formElement" xsi:type="string">date</item>
            <item name="dataScope" xsi:type="string">time_field</item>
            <item name="component" xsi:type="string">Your_Module/js/form/element/time</item>
        </item>
    </argument>
</field>

#2 Create the UI Component

// app/code/Your/Module/view/adminhtml/web/js/form/element/time.js

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

    return Date.extend({
        defaults: {
            options: {
                showsDate: false,
                showsTime: true,
                timeOnly: true
            },

            elementTmpl: 'ui/form/element/date'
        }
    });
});

A few notes on the above Javascript:

elementTmpl is not necessary. However, if you want to customize the template (currently module-ui/view/base/web/templates/form/element/date.html), just create your own template and reference it with elementTmpl.

Ref : Magento 2 Show timepicker using UiComponent not Datepicker

Aasim Goriya
  • 5,444
  • 2
  • 28
  • 53
0

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