23

I want to add new field as datetime in CMS page section while adding new page, I found that magento using UI Component for it, so after digging I could able to add the date field by using below code but not able to add datetime field. Can anybody help on it.

Code for add date field:

<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">Go Live Start Date</item>
            <item name="formElement" xsi:type="string">date</item>
            <item name="source" xsi:type="string">page</item>
            <item name="sortOrder" xsi:type="number">21</item>
            <item name="dataScope" xsi:type="string">start_date</item>
            <item name="validation" xsi:type="array">
                <item name="required-entry" xsi:type="boolean">true</item>
            </item>
        </item>
    </argument>
</field>

File we need to override to achieve:

vendor/magento/module-cms/view/adminhtml/ui_component/cms_block_form.xml
Siarhey Uchukhlebau
  • 15,957
  • 11
  • 54
  • 83
MagentoDev
  • 403
  • 1
  • 3
  • 10

3 Answers3

46

To add the dateTime picker you should use the next directive inside the xml file:

<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">Go Live Start Date</item>
            <item name="formElement" xsi:type="string">date</item>
            <item name="source" xsi:type="string">page</item>
            <item name="sortOrder" xsi:type="number">21</item>
            <item name="dataScope" xsi:type="string">start_date</item>
            <item name="validation" xsi:type="array">
                <item name="required-entry" xsi:type="boolean">true</item>
            </item>
            <item name="options" xsi:type="array">
                <item name="dateFormat" xsi:type="string">yyyy-MM-dd</item>
                <item name="timeFormat" xsi:type="string">HH:mm:ss</item>
                <item name="showsTime" xsi:type="boolean">true</item>
            </item>
            <item name="storeTimeZone" xsi:type="string">string</item>
        </item>
    </argument>
</field>

Important thing is the showsTime option.

Result should look like this:

date-time ui element result

If you want to debug the UI element - use this command inside the browser console (on your page):

require('uiRegistry').get('index = start_date')

It returns your date element with all initial options and all possible functions:

UI element object

You can use them when you define the element (inside xml).

As additional info:

The date (also dateTime) element could be found here:

app/code/Magento/Ui/view/base/web/js/form/element/date.js

in the static files:

pub/static/adminhtml/Magento/backend/en_US/Magento_Ui/js/form/element/date.js

The date-element class (object) has method prepareDateTimeFormats, where the important option showsTime is checked:

/**
 * Prepares and converts all date/time formats to be compatible
 * with moment.js library.
 */
prepareDateTimeFormats: function () {
    this.pickerDateTimeFormat = this.options.dateFormat;
if (this.options.showsTime) {
    this.pickerDateTimeFormat += ' ' + this.options.timeFormat;
}

this.pickerDateTimeFormat = utils.normalizeDate(this.pickerDateTimeFormat);

if (this.dateFormat) {
    this.inputDateFormat = this.dateFormat;
}

this.inputDateFormat = utils.normalizeDate(this.inputDateFormat);
this.outputDateFormat = utils.normalizeDate(this.outputDateFormat);

this.validationParams.dateFormat = this.outputDateFormat;

}

Siarhey Uchukhlebau
  • 15,957
  • 11
  • 54
  • 83
  • What is if I want to show only time picker? @Siarhey – Ronak Chauhan Jan 11 '17 at 06:55
  • @RonakChauhan You need another custom element because the DateTime element always renders date. – Siarhey Uchukhlebau Jan 11 '17 at 07:09
  • but how to do that? – Ronak Chauhan Jan 11 '17 at 07:10
  • @RonakChauhan You should extend the abstract UI-element and use something like .timepicker() – Siarhey Uchukhlebau Jan 11 '17 at 07:14
  • @RonakChauhan If You don't know how to do that it's better to ask a different question. – Siarhey Uchukhlebau Jan 11 '17 at 07:27
  • I have already asked the question http://magento.stackexchange.com/questions/154140/magento-2-show-timepicker-using-uicomponent – Ronak Chauhan Jan 11 '17 at 07:29
  • Could you tell me how to add color picker in ui form ??? – Sameer Bhayani Aug 16 '17 at 09:45
  • @SameerBhayani Yes, I can. But, please, ask a different question and send me a link. – Siarhey Uchukhlebau Aug 16 '17 at 10:27
  • https://magento.stackexchange.com/questions/189020/magento-2-how-to-add-color-picker-in-ui-form?noredirect=1#comment261743_189020 – Sameer Bhayani Aug 16 '17 at 14:25
  • @SiarheyUchukhlebau Thanks for your answer, I have a question about your answer, could you give a help? Thanks. DateTime UI Component - adjust the timezone – Key Shang Oct 25 '17 at 07:14
  • 1
    Find the solution by myself, your answer has a wrong timeFormat, we need change hh:mm:ss to HH:mm:ss in the UI Componet, otherwise 03:00:00 PM will became 03:00:00 AM, lack 12 hours and you can not save the time of PM in the database table. – Key Shang Oct 25 '17 at 08:17
  • @Key Thank you for the investigation, I have updated my answer. – Siarhey Uchukhlebau Oct 25 '17 at 08:18
  • @SiarheyUchukhlebau this dateTime field is saving wrong date& time (01/12/2193 00:00:00). Console debugging shows it as initial time. Could you pls guide me how to save selected date and time? – Yogesh Agarwal Dec 25 '17 at 05:51
  • @SachinAgarwal I think you are using different date and time format. Detect a correct one for your store and change this lines: <item name="dateFormat" xsi:type="string">yyyy-MM-dd</item> <item name="timeFormat" xsi:type="string">HH:mm:ss</item> – Siarhey Uchukhlebau Dec 27 '17 at 15:02
  • I am not getting that date which I have selected in ui_form. I am getting date in UTC format by default in magento. I want to get actual date which I have selected in ui_form. Please help. – Emipro Technologies Pvt. Ltd. May 23 '18 at 13:32
  • I am also getting same problem. When the DateTime field is rendered it converts into UTC instead of my default time zone. Can someone help ? – Ahsan Horani Jan 25 '19 at 10:57
  • I have specified the dateFormat in my form element like below. <item name="options" xsi:type="array"> <item name="dateFormat" xsi:type="string">dd.M.yy</item> <item name="showsTime" xsi:type="boolean">true</item> </item> When i checked with require('uiRegistry').get('index = xxx') the dateFormat value is not updating as per the configuration value. It still showing the format of the current locale. – amesh Jun 27 '19 at 11:56
  • @EmiproTechnologiesPvt.Ltd. To get the time you actually input in UI, you should add: <item name="storeTimeZone" xsi:type="string">UTC</item> into the config array. Although it is stated to be default in the docs, it is only default in JS but earlier overwritten in PHP if not present. – Creepin Sep 10 '20 at 19:40
2

I hope this answer gives some idea about what you miss

I added the UI component of date time field through php (it works fine)

$fieldset->addField(
        'event_date',
        'date',
        [
            'name' => 'event_date',
            'label' => __('Date'),
            'title' => __('Date'),
            'required' => true,
            'date_format' => 'yyyy-MM-dd',
            'time_format' => 'hh:mm:ss'
        ]
);

easy for your reference

compare to your xml file all values are present except date_format and time_format so you can try to set the both value in your xml file

for more details please refer this full source code

Bilal Usean
  • 9,977
  • 14
  • 75
  • 122
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