I have a combobox in which one can select a certain time span, e.g.:
5 minutes
15 minutes
1 hour
2 hours
1 day
2 days
1 week
2 weeks
It always transmits the number of minutes to the server, but the user wouldn't understand what "10080" means (before you try to calculate: it's a week).
A new requirement is that the user should be able to type arbitrary values into that box. E.g. "20 minutes", "1 hour 5 minutes", "2h 5m" or "1d 6h 120m"; and that, if the field is set to a certain value (e.g. 75) programmatically, the field should show the correct string (1 hour 15 minutes)
So I have written a parser and a formatter function (see below), but how can I get my combobox to use these?
I already tried overriding the rawToValue/valueToRaw function pair, similar to what I found in the datefield
code:
rawToValue:function(rawValue) {
console.log('rawToValue');
console.log(rawValue);
return this.parse(rawValue) || rawValue || null;
},
valueToRaw:function(value) {
console.log('valueToRaw');
console.log(value);
return this.format(value);
},
but they are not called, I don't get any console log output.
These are the parser/formatter functions:
Ext.define('AlarmTimeField',{
extend:'Ext.form.field.ComboBox',
format:function(minutes) {
var a = [];
Ext.each(this.units, function(unit) {
if(minutes >= unit.minutes) {
var unitCount = Math.floor(minutes/unit.minutes);
console.log(unitCount);
minutes = minutes-unitCount*unit.minutes;
a.push("" + unitCount + " " + (unitCount==1?unit.singular:unit.plural));
}
});
return a.join(' ');
},
parse:function(input) {
if(!input) return 0;
var me=this,
inputSplit = input.split(' '),
value = 0,
lastNum = 0;
Ext.each(inputSplit,function(input) {
if(!input) return;
else if(Ext.isNumeric(input)) lastNum = input;
else if(Ext.isNumeric(input[0])) {
var inputUnit = input.slice(-1),
inputValue = input.slice(0,-1);
Ext.each(me.units,function(unit) {
if(inputUnit==unit.abbr) {
value+=unit.minutes*inputValue;
}
});
}
else {
Ext.each(me.units,function(unit) {
if(input==unit.singular || input==unit.plural || input==unit.abbr) {
value+=unit.minutes*lastNum;
}
});
}
});
return value;
},
units:[{
minutes:10080,
abbr:'w',
singular:'week',
plural:'weeks'
},{
minutes:1440,
abbr:'d',
singular:'day',
plural:'days'
},{
minutes:60,
abbr:'h',
singular:'hour',
plural:'hours'
},{
minutes:1,
abbr:'m',
singular:'minute',
plural:'minutes'
}]
});
The main idea is that Ext.form.field.ComboBox
value is actually instance of Ext.data.Model
, so your value and displayed value is just model attribute values and each time you change value / displayed value you have to update binded model instance (its my vision, correct me if I'm wrong).
I think that Ext.form.field.ComboBox.validator is nice place to parse manually inputted values (and you can instantly display error message if inputted value is incorrect), so you can override it like this:
validator: function (value) {
// TODO: Add regexp value format validator
var minutes = me.parse(value);
// Add check for zero / empty values if needed
if (minutes === 0)
// Add meaningful error message
return 'Incorrect input';
else {
me.setValue(Ext.create('Ext.data.Model', {
value: minutes,
text: value
}));
return true;
}
}
Its quite raw example, but I think that idea is clear.
To format values setted programatically via setValue()
method you can override this method, like this:
setValue: function (value) {
// TODO: Add array of values support
if (Ext.isNumber(value))
value = Ext.create('Ext.data.Model', {
value: value,
text: this.format(value)
});
this.callParent([value]);
}
Check this fork of your fiddle. I hope that I helped a little.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With