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
4

3 Answers 3

46
+50

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;
}
18
  • What is if I want to show only time picker? @Siarhey Jan 11, 2017 at 6:55
  • @RonakChauhan You need another custom element because the DateTime element always renders date. Jan 11, 2017 at 7:09
  • but how to do that? Jan 11, 2017 at 7:10
  • @RonakChauhan You should extend the abstract UI-element and use something like .timepicker() Jan 11, 2017 at 7: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, 2017 at 8:17
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

2
  • Can you go through "vendor/magento/module-cms/view/adminhtml/ui_component/cms_block_form.xml" file and let me know how can I integrate the above code.
    – MagentoDev
    Aug 17, 2016 at 10:32
  • How can I change source to my custom name ? What requirements are here ? Nov 19, 2016 at 19:31
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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.