Sencha Touch TimePicker form field and Picker sheet
Currently we are using Sencha Touch as the basis for our new splog.me app.The Sencha Touch 1.1 framework includes a very large number of readily available form fields including the DatePicker form field and DatePicker popup sheet itself. Strangely enough, a TimePicker is missing so we decided to build one ourselves. The TimePicker below is heavily based on the DatePicker classes and includes a form field and a picker.
Ext.ux.form.TimePicker
To quickly demonstrate, the screenshots below show a TimePicker without any custom configuration and one that only shows a certain timespan and shows every fifth minute.
Usage
The TimePicker can be inserted into a form using it’s xtype ‘timepickerfield’ or by creating an instance yourselve.
var startTime = new Ext.ux.form.TimePicker({
name : 'starttime',
label: 'Start time'
});
Or it can be customized with the starting hour, ending hour and minute interval:
var startTime = new Ext.ux.form.TimePicker({
name : 'starttime',
label: 'Start time',
minuteScale: 5,
hourFrom: 8,
hourTo: 18,
value: {
hour: (new Date().getHours()+1)%24, /* start with the next hour */
minute: 0
}
});
Feel free to use the timepicker in your Sencha Touch app and let me know when you do. Always nice to see other great mobile apps. If you think of any improvements (EG. making it configurable for 24h/ AM PM format), let me know also. The code is displayed below and attached to this post as a tgz archive.
Cheers,
Rob
Code
Ext.ux.Form.TimePicker
Ext.ns('Ext.ux.form');
/**
* @class Ext.ux.form.TimePicker
* @extends Ext.form.Field
*
Specialized field which has a button which when pressed, shows a {@link Ext.ux.TimePicker}.
* @xtype timepickerfield
*/
Ext.ux.form.TimePicker = Ext.extend(Ext.form.Field, {
ui: 'select',
/**
* @cfg {Number} minuteScale
* List every how many minutes, eg. 5 lists 0, 5, 10, 15, etc. Defaults to 1
*/
minuteScale: 1,
/**
* @cfg {Number} hourFrom
* The start hour for the time picker. Defaults to 0
*/
hourFrom: 0,
/**
* @cfg {Number} hourTo
* The last hour for the time picker. Defaults to 23
*/
hourTo: 23,
/**
* @cfg {Object/Ext.ux.TimePicker} picker
* An object that is used when creating the internal {@link Ext.ux.TimePicker} component or a direct instance of {@link Ext.ux.TimePicker}
* Defaults to null
*/
picker: null,
/**
* @cfg {Object/Time} value
* Default value for the field and the internal {@link Ext.ux.TimePicker} component. Accepts an object of 'hour',
* and 'minute' values, all of which should be numbers, or a Time string.
*
* Example: {hour: 18, minute: 15} = 18:15
*/
/**
* @cfg {Boolean} destroyPickerOnHide
* Whether or not to destroy the picker widget on hide. This save memory if it's not used frequently,
* but increase delay time on the next show due to re-instantiation. Defaults to false
*/
destroyPickerOnHide: false,
// @cfg {Number} tabIndex @hide
// @cfg {Boolean} useMask @hide
// @private
initComponent: function() {
this.addEvents(
/**
* @event change
* Fires when a Time is selected
* @param {Ext.ux.form.TimePicker} this
* @param {Time} Time The new Time
*/
'change'
);
this.tabIndex = -1;
this.useMask = true;
Ext.form.Text.superclass.initComponent.apply(this, arguments);
},
/**
* Get an instance of the internal Time picker; will create a new instance if not exist.
* @return {Ext.ux.TimePicker} TimePicker
*/
getTimePicker: function() {
if (!this.timePicker) {
if (this.picker instanceof Ext.ux.TimePicker) {
this.timePicker = this.picker;
} else {
this.timePicker = new Ext.ux.TimePicker(Ext.apply(this.picker || {
minuteScale: this.minuteScale,
hourFrom: this.hourFrom,
hourTo: this.hourTo
}));
}
this.timePicker.setValue(this.value || null);
this.timePicker.on({
scope : this,
change: this.onPickerChange,
hide : this.onPickerHide
});
}
return this.timePicker;
},
/**
* @private
* Listener to the tap event of the mask element. Shows the internal {@link #timePicker} component when the button has been tapped.
*/
onMaskTap: function() {
if (Ext.ux.form.TimePicker.superclass.onMaskTap.apply(this, arguments) !== true) {
return false;
}
this.getTimePicker().show();
},
/**
* Called when the picker changes its value
* @param {Ext.ux.TimePicker} picker The time picker
* @param {Object} value The new value from the time picker
* @private
*/
onPickerChange : function(picker, value) {
this.setValue(value);
this.fireEvent('change', this, this.getValue());
},
/**
* Destroys the picker when it is hidden, if
* {@link Ext.ux.form.icker#destroyPickerOnHide destroyPickerOnHide} is set to true
* @private
*/
onPickerHide: function() {
if (this.destroyPickerOnHide && this.timePicker) {
this.timePicker.destroy();
}
},
// inherit docs
setValue: function(value, animated) {
if (this.timePicker) {
this.timePicker.setValue(value, animated);
this.value = (value != null) ? this.timePicker.getValue() : null;
} else {
if (Ext.isObject(value)) {
var hour = value.hour+"";
hour = hour.length == 1 ? 0 + hour : hour;
var minute = value.minute+"";
minute = minute.length == 1 ? 0 + minute : minute;
this.value = hour+":"+minute;
} else {
this.value = value;
}
}
if (this.rendered) {
this.fieldEl.dom.value = this.getValue(true);
}
return this;
},
/**
* Returns the value of the field, which will be a {@link Time} unless the format parameter is true.
* @param {Boolean} format True to format the value with Ext.util.Format.defaultTimeFormat
*/
getValue: function(format) {
var value = this.value || null;
if (Ext.isObject(value)) {
var hour = value.hour+"";
hour = hour.length == 1 ? 0 + hour : hour;
var minute = value.minute+"";
minute = minute.length == 1 ? 0 + minute : minute;
return hour+":"+minute;
}
return value;
},
// @private
onDestroy: function() {
if (this.timePicker) {
this.timePicker.destroy();
}
Ext.ux.form.TimePicker.superclass.onDestroy.call(this);
}
});
Ext.reg('timepickerfield', Ext.ux.form.TimePicker);
Ext.ux.Form.TimePicker
Ext.ns('Ext.ux');
/**
* @class Ext.ux.TimePicker
* @extends Ext.Picker
*
*
A time picker component which shows a TimePicker on the screen. This class extends from {@link Ext.Picker} and {@link Ext.Sheet} so it is a popup.
*
This component has no required properties.
*
*
<h2>Useful Properties</h2>
*
<ul class="list">
*
<li>{@link #hourFrom}</li>
*
<li>{@link #hourTo}</li>
*
</ul>
*
*
<h2>Example code:</h2>
*
*
<pre><code>
var timePicker = new Ext.ux.TimePicker();
timePicker.show();
* </code></pre>
*
*
you may want to adjust the {@link #hourFrom}, {@link #hourTo} and {@link #minuteScale} properties:
*
<pre><code>
var timePicker = new Ext.ux.TimePicker({
hourFrom: 8,
hourTo : 18,
minuteScale: 5
});
timePicker.show();
* </code></pre>
*
* @constructor
* Create a new Timepicker
* @param {Object} config The config object
* @xtype timepicker
*/
Ext.ux.TimePicker = Ext.extend(Ext.Picker, {
/**
* @cfg {Number} minuteScale
* List every how many minutes, eg. 5 lists 0, 5, 10, 15, etc. Defaults to 1
*/
minuteScale: 1,
/**
* @cfg {Number} hourFrom
* The start hour for the time picker. Defaults to 0
*/
hourFrom: 0,
/**
* @cfg {Number} hourTo
* The last hour for the time picker. Defaults to 23
*/
hourTo: 23,
/**
* @cfg {String} hourText
* The label to show for the hour column. Defaults to 'Hour'.
*/
hourText: 'Hour',
/**
* @cfg {String} minuteText
* The label to show for the minute column. Defaults to 'Minute'.
*/
minuteText: 'Minute',
/**
* @cfg {Array} slotOrder
* An array of strings that specifies the order of the slots. Defaults to <tt>['hour', 'minute']</tt>.
*/
slotOrder: ['hour', 'minute'],
initComponent: function() {
var hoursFrom = this.hourFrom,
hoursTo = this.hourTo,
hours = [],
minutes = [],
ln, tmp, i, j;
// swap values if user mixes them up.
if (hoursFrom > hoursTo) {
tmp = hoursFrom;
hoursFrom = hoursTo;
hoursTo = tmp;
}
for (i = j = hoursFrom; i <= hoursTo; i++, j++) { j = (j+"").length > 1 ? j : "0"+j;
hours.push({
text: j,
value: i
});
}
for (i = j = 0; i <= 59; i = j = i + this.minuteScale) { j = (j+"").length > 1 ? j : "0"+j;
minutes.push({
text: j,
value: i
});
}
this.slots = [];
this.slotOrder.forEach(function(item){
this.slots.push(this.createSlot(item, hours, minutes ));
}, this);
Ext.ux.TimePicker.superclass.initComponent.call(this);
},
afterRender: function() {
Ext.ux.TimePicker.superclass.afterRender.apply(this, arguments);
this.setValue(this.value);
},
createSlot: function(name, hours, minutes ){
switch (name) {
case 'hour':
return {
name: name,
align: 'right',
data: hours,
title: this.useTitles ? this.hourText : false,
flex: 5
};
case 'minute':
return {
name: name,
align: 'left',
data: minutes,
title: this.useTitles ? this.minuteText : false,
flex: 5
};
}
},
// @private
onSlotPick: function(slot, value) {
Ext.ux.TimePicker.superclass.onSlotPick.apply(this, arguments);
},
/**
* Gets the current value as a Time object
* @return {hour: x, minute: y} value
*/
getValue: function() {
var value = Ext.ux.TimePicker.superclass.getValue.call(this);
return value;
},
/**
* Sets the values of the TimePicker's slots
* @param {Date/Object} value The value either in a {hour:'value', minute:'value'} format or a String, eg: '18:00'
* @param {Boolean} animated True for animation while setting the values
* @return {Ext.DatePicker} this This DatePicker
*/
setValue: function(value, animated) {
if (Ext.isObject(value)) {
this.value = value;
} else {
var arr = (value+"").split(':');
this.value = {
hour: parseInt(arr[0],10),
minute: parseInt(arr[1],10)
};
}
return Ext.ux.TimePicker.superclass.setValue.call(this, this.value, animated);
}
});
Ext.reg('timepicker', Ext.ux.TimePicker);
9 Responses to Sencha Touch TimePicker form field and Picker sheet
Leave a Reply Cancel reply
POST CATEGORIES
ExtJS
- Sencha.com Sencha.com – creators of ExtJS and Sencha Touch









Hey Rob, Thanks a lot for this ! saved me plenty of time and works great!
The picker component does not seem to work, so I had to inherit from Ext.Sheet instead. Now I can’t seem to get a default value inserted into the picker. I can set the default values (hour and minute), but for some reason the picker values are set to 00:00 instead of the default values I set.
I would be really happy if you could provide me with a solution to this problem, or point me to where (in the code) the default value is set inside the picker.
Hi Jacob,
I will be happy to look into it, first off, which version of Sencha Touch are you using? This picker is based on 1.1
I’m using Sencha Touch 1.1.0, so that shouldn’t be a problem. Also, what I’ve noticed is that the picker seems to get the correct time after I’ve picked a time once, but it does not get the correct time if I’ve set a default time.
I’m aware that it could be my fault as I’ve done some changes in order to make the picker work at all, but I still need to know where to find the code where the picker gets/sets its default values
If you don’t check the comments very often it would be great if you could email me instead. My email address is jakob.grannas@intelliplan.se. I need to fix this asap, so it would really help you could reply as soon as you read this.
Thank you very much
Rob – what is the best way to integrate these classes into Sencha Touch? I tried dropping into src folder, but figured that sencha-touch.js needs to reference this new components somehow. Or should you just directly include – ?
Hi Chris,
In my production environment I concatenate all Sencha sources and my own custom sources using Sencha build and some custom perl scripts. For my development environment everything is just included into the index.html file in this order:
- sencha-touch.js
- UX classes (including my own, this also includes the time picker)
- app.js
- utils
- models
- stores
- views
- controllers
I built a perl script that scans my sources and automatically creates the index.html file for me (among other things). If you like I can send you an example of this index.html file. Hope this helps.
Hi Robb,
I have still not figured out how to get the make the picker set its values to my default values. I’ve console.log:ged this.value practically everywhere in the code, and it always seems to be correct, but the picker still has 00:00 set upon instantiation. I really need your help, and would really appreciate if you could answer my questions.
Thanks a lot. Saved me a lot of work. Works out of the box.