PDA

View Full Version : Cleared datefield still posts date



djSeverin
7 Dec 2009, 4:44 PM
Version is latest from ExtJS Svn for 3.0.x branch as at 13/11/2009;
Adapter is Ext;
Browser is Firefox 3.5.2

==== QUESTION =============================================

I am using two datefield's to specify Start and End dates for a reporting app.

PROBLEM:
* datefield is populated with a date (either via date picker or keyboard);
* the date that was entered gets POSTed, even if the datefield has been cleared ...

By "cleared", I mean backspacing or highlighting the date and pressing delete, leaving the date field empty (containing no visible value).

This behavior seems incorrect. Is this just me experiencing this or is this the way its supposed to be? :-?

I have checked to ensure there are no dupicate ID's etc.

I have also been searching the forums and it seems that everyone that runs into this just tacks on a "clear" button.


==== CODE SNIPPIT ==========================================


{
xtype : 'fieldset',
title : 'Report Dates',
layout :'column',
anchor :'-20',
items:[{
columnWidth :.5,
layout: 'form',
items : [
{
xtype : 'datefield',
format : 'd/m/Y',
fieldLabel : 'Start Date',
id : 'report_startDate',
vtype : 'daterange',
endDateField : 'report_endDate',
anchor : '-10',
allowBlank : true
}
]
},{
columnWidth :.5,
layout: 'form',
items : [{
xtype : 'datefield',
format : 'd/m/Y',
fieldLabel : 'End Date',
id : 'report_endDate',
vtype : 'daterange',
startDateField : 'report_startDate',
anchor : '-10',
allowBlank : true
}]
}]
}

mystix
8 Dec 2009, 12:46 AM
try this override:


Ext.override(Ext.form.DateField, {
beforeBlur : function(){
this.setValue(this.parseDate(this.getRawValue()) || null);
}
});



this should qualify as a bug imho.
you might want to file a bug report for it in the 3.x Bugs forum, with a link in the report back to this page.

djSeverin
8 Dec 2009, 9:38 PM
Thankyou for the suggestion mystix, worked nicely!

The problems associated with the way datefield's handle null appears to be a tad larger then just this particular case.

Datefield appears to bypass firing of an attached VType in the event it contains no data (null).

As such, a StartDate + EndDate pair bound by a vtype (such as "dateRange"), do not remove their partner's min/maxValue when their date value is cleared.

Hence, when the user clears their StartDate field, the EndDate's datepicker still bars them from choosing a date < the old start date. Even though the StartDate field is now blank.

Can you provide any clues as to where I should go looking to deal with this problem?

I've been looking at the source for the datefield but nothing I have tried has worked so far.

I hope that made sense. I haven't had much sleep recently ~o)

mystix
8 Dec 2009, 11:15 PM
i think that's likely a problem with the vtype itself.

the daterange vtype is set to return immediately when there's no value:


// ...

if(!date){
return;
}

// ...

so the startDate / endDate pair's min/maxValues are never updated.

try messing with the daterange vtype itself this time, and set breakpoints at suitable points within the daterange vtype just to make sure it's being called despite the start/end DateField having a null value.

djSeverin
8 Dec 2009, 11:26 PM
Sorry I wasn't overly clear in my post. I should have mentioned that I have narrowed the problem down to the vtype not firing at all.

I ended up placing an alert into the daterange vtype definition at the start of the function to prove this was the case.

The alert would fire if there was a date in the datefield. The alert would not fire if the datefield was blank.

===== VType definition being used to test with ==============================

Ext.apply(Ext.form.VTypes, {

daterange : function(val, field) {

var date = field.parseDate(val);
alert('val is: ' + val);

if (field.startDateField && (!this.dateRangeMax || (date.getTime() != this.dateRangeMax.getTime()))) {
var start = Ext.getCmp(field.startDateField);
start.setMaxValue(date);
start.validate();
this.dateRangeMax = date;
}
else if (field.endDateField && (!this.dateRangeMin || (date.getTime() != this.dateRangeMin.getTime()))) {
var end = Ext.getCmp(field.endDateField);
end.setMinValue(date);
end.validate();
this.dateRangeMin = date;
}

return true;

} // EO Daterange vtype def

});

mystix
8 Dec 2009, 11:34 PM
if you trace the validation routine back to TextField#validateValue, you'll see this


validateValue : function(value){
if(Ext.isFunction(this.validator)){
var msg = this.validator(value);
if(msg !== true){
this.markInvalid(msg);
return false;
}
}
if(value.length < 1 || value === this.emptyText){ // if it's blank
if(this.allowBlank){
this.clearInvalid();
return true;
}else{
this.markInvalid(this.blankText);
return false;
}
}

// ...

which explains why the daterange vtype isn't being called.

it appears that the only way to counter this behaviour (vtypes being bypassed when allowBlank: true) is to write a custom validator function. :-?

djSeverin
20 Dec 2009, 8:01 PM
Fixed in two parts and many thanks to Mystix for pointing me in the right direction.

Two parts:

====Override for dateField============================================

// Add override to fix the "Date field still posts data, even though blank" problem
// and ensure vType filters on dateField pairs fire correctly.
Ext.override(Ext.form.DateField, {

// Fix the "Date field still posts data, even though blank" problem
beforeBlur : function(){
this.setValue(this.parseDate(this.getRawValue()) || null);
},

// Override validateValue so as vType filter fires correctly when text fields are null
// this ensures that code to clear maxValue/minValue executes on vType paired dateFields
validateValue : function(value){

// Begin textfield based validation with overides to ensure vType filters execute
value = this.formatDate(value);

if(Ext.isFunction(this.validator)){
var msg = this.validator(value);
if(msg !== true){
this.markInvalid(msg);
return false;
}
}

if(this.vtype){
var vt = Ext.form.VTypes;
if(!vt[this.vtype](value, this)){
this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
return false;
}
}

if(this.regex && !this.regex.test(value)){
this.markInvalid(this.regexText);
return false;
}

// Begin dateField specific validation
var svalue = value;

if(value.length < 1){
// If textfield validators didn't flag it then assume it's valid mmm-k
return true;
}

value = this.parseDate(value);

if(!value){
this.markInvalid(String.format(this.invalidText, svalue, this.format));
return false;
}

var time = value.getTime();

if(this.minValue && time < this.minValue.getTime()){
this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
return false;
}

if(this.maxValue && time > this.maxValue.getTime()){
this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
return false;
}

if(this.disabledDays){
var day = value.getDay();
for(var i = 0; i < this.disabledDays.length; i++) {
if(day === this.disabledDays[i]){
this.markInvalid(this.disabledDaysText);
return false;
}
}
}

var fvalue = this.formatDate(value);

if(this.disabledDatesRE && this.disabledDatesRE.test(fvalue)){
this.markInvalid(String.format(this.disabledDatesText, fvalue));
return false;
}

return true;

} // EO validateValue override for paired dateFields with vType linkages

});


====Updated vType====================================================

// Add additional VType
Ext.apply(Ext.form.VTypes, {
daterange : function(val, field) {
var date = field.parseDate(val);

if(!date){
// Do some acrobatics to clear the start/end date blocks if a paired datefield is cleared
if (field.endDateField) {
var endDateBox = Ext.getCmp(field.endDateField);
endDateBox.setMinValue(null);
return true;
} else {
var startDateBox = Ext.getCmp(field.startDateField);
startDateBox.setMaxValue(null);
return true;
}
}

// Otherwise, go ahead and set paired datefield's min/maxValue
if (field.startDateField && (!this.dateRangeMax || (date.getTime() != this.dateRangeMax.getTime()))) {
var start = Ext.getCmp(field.startDateField);
start.setMaxValue(date);
start.validate();
this.dateRangeMax = date;
}
else if (field.endDateField && (!this.dateRangeMin || (date.getTime() != this.dateRangeMin.getTime()))) {
var end = Ext.getCmp(field.endDateField);
end.setMinValue(date);
end.validate();
this.dateRangeMin = date;
}

return true;
}
});