PDA

View Full Version : disable dates in datefield



roshniblr
11 Nov 2009, 12:09 AM
Hi,

If I want to disable dates starting from some date for e.g 02/15/03 to 02/03/03,
should I use mention all the dates in array from 02/15/03 to 02/03/03 and use in disabledates:?
The array size will be large i use this way. Is there some other way I can mention the starting date and ending date to disable all the dates between starting date and ending date?

BitPoet
11 Nov 2009, 2:27 AM
You could check in a custom validator function:


new Ext.form.DateField({
...,
validator: function(val) {
var svalue = this.parseDate(value);
if( svalue.between(this.parseDate('02/03/03','02/15/03')) ) {
return "The date is not in an allowed range";
}
}
});


Or, you could extend the DateField class to add a more intuitive interface and make it possible to set arbitrary ranges in the config object and use disabledDatesText for the messages:


Ext.override(Ext.form.DateField, {
disabledRanges: false,

validateValue : function(value){
value = this.formatDate(value);
if(!Ext.form.DateField.superclass.validateValue.call(this, value)){
return false;
}
if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
return true;
}
var svalue = value;
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.disabledRanges && Ext.isArray(this.disabledRanges) ) {
for(var i = 0; i < this.disabledRanges.length; i++) {
var rng = this.disabledRanges[i];
if(value.between(rng.start, rng.end)) {
this.markInvalid(this.disabledDatesText);
return false;
}
}
} else {
Ext.Msg.alert( 'Not set', 'No disabledRanges set' );
}
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;
},

initDisabledRanges : function() {
if( this.disabledDatesRanges && Ext.isArray(this.disabledDatesRanges) ) {
this.disabledRanges = [];
Ext.each(this.disabledDatesRanges, this.addDisabledRange, this);
}
},

addDisabledRange : function(range) {
if( Ext.isArray(range) && range.length == 2 ) {
var rstart = Ext.isDate(range[0]) ? range[0] : this.parseDate(range[0]);
var rend = Ext.isDate(range[1]) ? range[1] : this.parseDate(range[1]);
this.disabledRanges.push( { start: rstart, end: rend } );
}
}

});
Ext.form.DateField.prototype.initComponent = Ext.form.DateField.prototype.initComponent.createSequence(function(){
this.disabledRanges = null;
this.initDisabledRanges();
});


And then use something like:


new Ext.form.DateField({
id: 'df',
name: 'df',
width: 120,
format: 'Y-m-d',
msgTarget: 'under',
disabledDatesText: 'This date has been disabled',
disabledDatesRanges: [
[ '2009-10-01', '2009-10-15' ],
[ '2009-11-10', '2009-11-20' ]
]
});

roshniblr
12 Nov 2009, 3:48 AM
Will validateValue() will help me to keep the default validations provided by extjs also?
I also want when the disable the dates, in the popup calendar the dates will be disabled.
So some how it will be better if I use disableDates attribute. But how do I set this disableDates attribute with the dates between two given dates?

BitPoet
12 Nov 2009, 6:02 AM
Will validateValue() will help me to keep the default validations provided by extjs also?

Yes, custom validators are just called before the regular validation methods.


I also want when the disable the dates, in the popup calendar the dates will be disabled.
So some how it will be better if I use disableDates attribute. But how do I set this disableDates attribute with the dates between two given dates?

You could either add an entry for each date in the range, or construct one or more regular expressions that cover the whole range - not very flexible and intuitive though.

I've hacked my override a bit to include support for disabled date ranges in the picker, the functionality needs to be implemented in the DatePicker class and support for passing the disabledDatesRanges to the picker added in the DateField:


Ext.override(Ext.DatePicker, {
update : function(date, forceRefresh){
var vd = this.activeDate, vis = this.isVisible();
this.activeDate = date;
if(!forceRefresh && vd && this.el){
var t = date.getTime();
if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
this.cells.removeClass('x-date-selected');
this.cells.each(function(c){
if(c.dom.firstChild.dateValue == t){
c.addClass('x-date-selected');
if(vis){
Ext.fly(c.dom.firstChild).focus(50);
}
return false;
}
});
return;
}
}
var days = date.getDaysInMonth();
var firstOfMonth = date.getFirstDateOfMonth();
var startingPos = firstOfMonth.getDay()-this.startDay;

if(startingPos <= this.startDay){
startingPos += 7;
}

var pm = date.add('mo', -1);
var prevStart = pm.getDaysInMonth()-startingPos;

var cells = this.cells.elements;
var textEls = this.textNodes;
days += startingPos;

// convert everything to numbers so it's fast
var day = 86400000;
var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
var today = new Date().clearTime().getTime();
var sel = date.clearTime().getTime();
var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
var ddMatch = this.disabledDatesRE;
var ddText = this.disabledDatesText;
var ddays = this.disabledDays ? this.disabledDays.join('') : false;
var ddaysText = this.disabledDaysText;
var ddRanges = this.disabledRanges;
var format = this.format;

if(this.showToday){
var td = new Date().clearTime();
var disable = (td < min || td > max ||
(ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
(ddays && ddays.indexOf(td.getDay()) != -1));

if(!this.disabled){
this.todayBtn.setDisabled(disable);
this.todayKeyListener[disable ? 'disable' : 'enable']();
}
}

var setCellClass = function(cal, cell){
cell.title = '';
var t = d.getTime();
cell.firstChild.dateValue = t;
if(t == today){
cell.className += ' x-date-today';
cell.title = cal.todayText;
}
if(t == sel){
cell.className += ' x-date-selected';
if(vis){
Ext.fly(cell.firstChild).focus(50);
}
}
// disabling
if(t < min) {
cell.className = ' x-date-disabled';
cell.title = cal.minText;
return;
}
if(t > max) {
cell.className = ' x-date-disabled';
cell.title = cal.maxText;
return;
}
if(ddays){
if(ddays.indexOf(d.getDay()) != -1){
cell.title = ddaysText;
cell.className = ' x-date-disabled';
return;
}
}
if(ddRanges) {
for( var i = 0; i < ddRanges.length; i++ ) {
if( d.between(ddRanges[i].start, ddRanges[i].end) ) {
cell.title = ddaysText;
cell.className = ' x-date-disabled';
return;
}
}
}
if(ddMatch && format){
var fvalue = d.dateFormat(format);
if(ddMatch.test(fvalue)){
cell.title = ddText.replace('%0', fvalue);
cell.className = ' x-date-disabled';
}
}
};

var i = 0;
for(; i < startingPos; i++) {
textEls[i].innerHTML = (++prevStart);
d.setDate(d.getDate()+1);
cells[i].className = 'x-date-prevday';
setCellClass(this, cells[i]);
}
for(; i < days; i++){
var intDay = i - startingPos + 1;
textEls[i].innerHTML = (intDay);
d.setDate(d.getDate()+1);
cells[i].className = 'x-date-active';
setCellClass(this, cells[i]);
}
var extraDays = 0;
for(; i < 42; i++) {
textEls[i].innerHTML = (++extraDays);
d.setDate(d.getDate()+1);
cells[i].className = 'x-date-nextday';
setCellClass(this, cells[i]);
}

this.mbtn.setText(this.monthNames[date.getMonth()] + ' ' + date.getFullYear());

if(!this.internalRender){
var main = this.el.dom.firstChild;
var w = main.offsetWidth;
this.el.setWidth(w + this.el.getBorderWidth('lr'));
Ext.fly(main).setWidth(w);
this.internalRender = true;
// opera does not respect the auto grow header center column
// then, after it gets a width opera refuses to recalculate
// without a second pass
if(Ext.isOpera && !this.secondPass){
main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + 'px';
this.secondPass = true;
this.update.defer(10, this, [date]);
}
}
}
});


Ext.override(Ext.form.DateField, {
disabledRanges: false,

onTriggerClick : function(){
if(this.disabled){
return;
}
if(this.menu == null){
this.menu = new Ext.menu.DateMenu({
hideOnClick: false
});
}
this.onFocus();
Ext.apply(this.menu.picker, {
minDate : this.minValue,
maxDate : this.maxValue,
disabledDatesRE : this.disabledDatesRE,
disabledDatesText : this.disabledDatesText,
disabledDays : this.disabledDays,
disabledDaysText : this.disabledDaysText,
disabledRanges : this.disabledRanges,
format : this.format,
showToday : this.showToday,
minText : String.format(this.minText, this.formatDate(this.minValue)),
maxText : String.format(this.maxText, this.formatDate(this.maxValue))
});
this.menu.picker.setValue(this.getValue() || new Date());
this.menu.show(this.el, "tl-bl?");
this.menuEvents('on');
},

validateValue : function(value){
value = this.formatDate(value);
if(!Ext.form.DateField.superclass.validateValue.call(this, value)){
return false;
}
if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
return true;
}
var svalue = value;
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.disabledRanges && Ext.isArray(this.disabledRanges) ) {
for(var i = 0; i < this.disabledRanges.length; i++) {
var rng = this.disabledRanges[i];
if(value.between(rng.start, rng.end)) {
this.markInvalid(this.disabledDatesText);
return false;
}
}
} else {
Ext.Msg.alert( 'Not set', 'No disabledRanges set' );
}
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;
},

initDisabledRanges : function() {
if( this.disabledDatesRanges && Ext.isArray(this.disabledDatesRanges) ) {
this.disabledRanges = [];
Ext.each(this.disabledDatesRanges, this.addDisabledRange, this);
}
},

addDisabledRange : function(range) {
if( Ext.isArray(range) && range.length == 2 ) {
var rstart = Ext.isDate(range[0]) ? range[0] : this.parseDate(range[0]);
var rend = Ext.isDate(range[1]) ? range[1] : this.parseDate(range[1]);
this.disabledRanges.push( { start: rstart, end: rend } );
}
}

});
Ext.form.DateField.prototype.initComponent = Ext.form.DateField.prototype.initComponent.createSequence(function(){
this.disabledRanges = null;
this.initDisabledRanges();
});


Not a very pretty override, I guess this code could be prettified a lot. A possibility to pass the validator function on to the DatePicker would go a long way there.

moegal
11 Apr 2010, 9:54 AM
Did you ever got this to work. I have tried your example and I get errors. I need to add date ranges that are disabled in the picker as well.

I am using 3.1+

Thanks, Marty

Ryan Mendoza
30 Jun 2011, 8:29 AM
Hello,

I was curious if there is any update to this in order to get it to work with v3.3?

When attempting to use override I get "Cannot read property 'elements' of undefined" for the line "var cells = this.cells.elements;"