Yes, you should be able to use as many template bindings as you want. You could do this with a string identifier for the template URN
<!-- ko template: "Package_Namespace/template-name" --><!-- /ko -->
or a property on your view model that contains a template string.
<!-- ko template: someProp --><!-- /ko -->
You can also use the above with a <script type="text/html"
named template, as per the Knockout docs
If you're unfamiliar with how Knockout template URNs or text/html
named templates work in Magento, I cover it OK in my Magento 2: KnockoutJS Integration article. I've also got a comprehensive series on UI Components and their underlying uiElement objects if you want to go really deep.
Here's a way to do it by making a custom ui component. It requires the backing field to be a varchar.
Define the ui component in 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;
})()
});
});
and the template, in 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}"/>
Use it in your form xml like this:
<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>
The value from the two drop downs is merged to produce a string like '0130'
to represent the time 1:30
, so your data type needs to be varchar otherwise the leading '0' will be dropped.
Best Answer
If I've understood this correctly you have added a function to
onUpdate
which works fine, but it isn't working on page load?If this is the case then it's because you have only informed the browser so run your code when a change occurs, if you want it to happen on page load you'll also need to do it on initialisation like so:
And your code isn't waiting for page load, if you want this to happen you need to add
domReady!
as a dependency.