Suggested case list:
Using timer to refresh a grid
383guest172.69.33.12125nk0uiMay 7, 2020 7:23:47 AMlinkuser model to move item to another listbox
120guest162.158.193.148d0n3krApr 2, 2020 5:28:28 AMlinkDisabled list item row passed to VM-1981
296fatih123160.83.36.13025nk0uiFeb 13, 2018 4:25:44 PMlinkDisabled list item row passed to VM-1981
295fatih123160.83.36.13025nk0uiFeb 13, 2018 4:25:16 PMlinkDisabled list item row passed to VM-1981
294fatih123160.83.36.13225nk0uiFeb 13, 2018 3:30:44 PMlinkgrid sample with ListModel/RowRenderer
816guest80.82.2.1312vah9ajFeb 21, 2017 11:42:21 AMlinkgrid sample with ListModel/RowRenderer
809guest175.98.113.1622vah9ajJan 26, 2017 9:19:33 AMlinkgrid sample with ListModel/RowRenderer
196guest79.185.142.402vah9ajApr 26, 2014 10:53:57 PMlinkgrid sample with ListModel/RowRenderer
195guest79.185.142.402vah9ajApr 26, 2014 10:53:54 PMlinkgrid sample with ListModel/RowRenderer
194guest79.185.142.402vah9ajApr 26, 2014 10:53:51 PMlinkgrid sample with ListModel/RowRenderer
193guest79.185.142.402vah9ajApr 26, 2014 10:53:48 PMlinkgrid sample with ListModel/RowRenderer
192guest79.185.142.402vah9ajApr 26, 2014 10:53:44 PMlinkgrid sample with ListModel/RowRenderer
191guest79.185.142.402vah9ajApr 26, 2014 10:53:40 PMlinkHierarchy table without using ZK PE/EE
1aaknai151.28.135.2131s871daJul 29, 2013 11:02:46 PMlinkgrid sample with ListModel/RowRenderer
128aaknai151.28.135.2132vah9ajJul 29, 2013 7:20:00 PMlinkuser model to move item to another listbox
1TonyQ114.25.109.94d0n3krApr 21, 2012 10:43:27 AMlinkUsing timer to refresh a grid
1TonyQ220.133.44.3725nk0uiFeb 17, 2012 3:17:34 AMlinkFire a event from child iframe
1TonyQ220.133.44.372eupjotFeb 3, 2012 5:04:52 AMlinkTextbox input restriction sample
1TonyQ72.21.245.2431b3nlr0Dec 20, 2011 10:09:10 AMlinkTest web core taglib in ZUL
1TonyQ198.203.175.175ofqkemDec 17, 2011 3:36:08 AMlinkLatest 10 Fiddles :
constraint binding textbox
3guest172.68.151.16220peldaDec 5, 2025 5:08:19 PMlinkAnother new ZK fiddle
2guest172.68.151.16320peldaDec 5, 2025 5:07:51 PMlinkAnother new ZK fiddle
1guest172.68.151.16220peldaDec 5, 2025 5:07:32 PMlinkAnother new ZK fiddle
1peggypeng172.71.154.99364f4neDec 5, 2025 9:24:31 AMlinktooltip example
2guest104.22.23.13rc1ntoDec 4, 2025 2:23:45 PMlinkAnother new ZK fiddle
1guest172.69.134.2277t7602Dec 4, 2025 1:40:46 PMlinkAnother new ZK fiddle
1peggypeng104.22.17.1802df6e3oDec 4, 2025 8:41:29 AMlinkonClose
1peggypeng172.68.87.248j8kd8aDec 3, 2025 4:10:26 AMlinkAnother new ZK fiddle
1peggypeng172.69.134.2271rm7f4eNov 26, 2025 3:31:24 AMlinkZK-5912-Suggestion
2rebeccalai104.22.20.1442qrmiiuNov 26, 2025 2:07:15 AMlinkAnother new ZK fiddle
5guest172.70.214.952ho5egMay 2, 2022 5:22:04 AMlinkresources
index.zulzul<?script src="./datetimeOverride.js" ?>
<zk>
<div>
<datebox format="yyyy-MM-dd" />
</div>
</zk>
datetimeOverride.jsjavascript/*
* Copyright (c) 2018 Navis LLC. All Rights Reserved.
*
*/
// Overrides for the datebox
zk.afterLoad('zul.db', function() {
var _zDate = {};
var dateboxFmtArr = null;
var currDateFmtCache = null;
var defaultParseDate = zk.fmt.Date.parseDate;
//callback utility can be used anywhere, this works like consumer in java8 lamda expression
var $callback = function (obj, func) {
return function () {
if (obj && func) {
func.apply(obj, arguments);
}
}
};
/**
* it parses the date format, it understand format which contains only
* [ dd or MM or yyyy]
* this converts it to d1, d2, M1, M2, y1, y2, y3, y4 each has several validations
* @param dateFmt
* @returns Array
*/
var parseDateFormatToArr = function (dateFmt) {
if (!dateboxFmtArr || currDateFmtCache != dateFmt) {
dateboxFmtArr = [];
var dateFmtRegex = /^(dd|MM|yyyy).(dd|MM|yyyy).(dd|MM|yyyy)$/g
var matches = dateFmtRegex.exec(dateFmt);
for (var i = 1; i < matches.length; i++) {
if (matches[i] == 'dd') {
dateboxFmtArr.push('d1', 'd2');
} else if (matches[i] == 'MM') {
dateboxFmtArr.push('M1', 'M2');
} else if (matches[i] == 'yyyy') {
dateboxFmtArr.push('y1', 'y2', 'y3', 'y4');
}
}
currDateFmtCache = dateFmt;
}
return dateboxFmtArr;
}
/**
* this parse the date text, it allows short date format
* date alone, month and date alone, month, year and date
* @param txt
* @param dateFmt
* @returns Date or null
*/
var plainDateParser = function (txt, dateFmt) {
var defaultval = null;
var canSkipYear = 0;
var dtFmts = parseDateFormatToArr(dateFmt);
var dateMonthGvn = function (inTxt, dtFmtsSlice) {
var dateGvn = 0;
var monthGvn = 0;
var char0 = parseInt(inTxt.charAt(0)), char1 = parseInt(inTxt.charAt(1));
if (dtFmtsSlice[0].startsWith('d')) {
if (char0 > 3 || (char0 == 3 && char1 > 1)) {
dateGvn = inTxt.substr(0, 1);
monthGvn = inTxt.substr(1, 2);
} else {
dateGvn = inTxt.substr(0, 2);
monthGvn = inTxt.substr(2);
}
} else {
if (char0 == 1 || char0 == 0) {
monthGvn = inTxt.substr(0, 2);
dateGvn = inTxt.substr(2);
} else {
monthGvn = inTxt.substr(0, 1);
dateGvn = inTxt.substr(1, 2);
}
}
return [dateGvn, monthGvn];
}
var checkValidDateForMonth = function (dateTxt, dateNow) {
var date = dateNow || new Date();
var dateGvn = parseInt(dateTxt);
var monthLastDate = (new Date(date.getFullYear(), date.getMonth() + 1, 0)).getDate();
if (dateGvn <= monthLastDate) {
date.setDate(dateGvn);
return date;
}
return defaultval;
}
//year is given in beginning of date format
if (dtFmts[0].startsWith('y')) {
canSkipYear = 1;
//year is at the end of date format
} else if (dtFmts[dtFmts.length - 1].startsWith('y')) {
canSkipYear = 2;
}
//full date is given as per the specified zone format
if (txt.length == 8) {
var regex = /1|2|3|4/gi;
var newFmt = dtFmts.join('').replace(regex, '');
var txtDate = defaultParseDate(txt, newFmt);
if (txtDate) {
return txtDate;
}
//considered they have entered only the date
} else if (txt.length <= 2) {
return checkValidDateForMonth(txt);
//considered they have entered month and date
} else if (canSkipYear && txt.length <= 4) {
var date = new Date();
var dtMonthGvn = dateMonthGvn(txt, canSkipYear == 1 ? dtFmts.slice(4) : dtFmts.slice(0, 4));
date.setMonth(parseInt(dtMonthGvn[1]) - 1);
return checkValidDateForMonth(dtMonthGvn[0], date);
//below will works for the date format ends with year ex:ddMMyyyy
//considered user given as short year
} else if (canSkipYear == 2 && txt.length == 6) {
var date = new Date();
var year = (parseInt(date.getFullYear() / 100) * 100) + parseInt(txt.substr(-2));
var dtMonthGvn = dateMonthGvn(txt.substr(0, 4), dtFmts.slice(0, 4));
date.setFullYear(year);
date.setMonth(parseInt(dtMonthGvn[1]) - 1);
return checkValidDateForMonth(dtMonthGvn[0], date);
}
return defaultval;
}
zk.override(zk.fmt.Date, _zDate, {
// Override the parse date
parseDate: function (txt, fmt, strict, refval, localizedSymbols) {
// Pattern for +### or -### with three digits
var patternPlusMinus = '^(\\+|-)\\d{0,3}$';
var patternPlainDate = '^[0-9]+$';
var currentDate = new Date();
this.rawInput = txt;
if (!txt || txt instanceof Date) {
return txt;
// Handles the 't' notation
} else if (txt === "t" || txt === "T") {
return currentDate;
// Handles the +1, -1 notation
} else if (txt.match(patternPlusMinus)) {
var operator = txt.substr(0, 1) === "+" ? 1 : -1;
var amount = txt.substr(1) || 0;
var dayOfMonth = currentDate.getDate();
currentDate.setDate(dayOfMonth + operator * parseInt(amount));
return currentDate;
} else if (txt.match(patternPlainDate)) {
return plainDateParser(txt, fmt);
//Handles if it is date given by date picker in the configured format
} else if (txt.length === fmt.length) {
var txtDate = defaultParseDate(txt, fmt);
if (txtDate) {
return txtDate;
}
}
return null;
}
});
var _zDatebox = {};
//dateboxAllowedKeyCodes = [t, T, +, -]
var dateboxAllowedKeyCodes = [116, 84, 45, 43];
/**
* Below are the various input values it allows
* t | +1 | -1 | any shuffled set of dd, MM, yyyy
* Example: yyyy/MM/dd or dd.MM.yyyy or yyyy-dd-MM
* this method first looks the region datebox date format and validates
* the next allowed character
*/
var identifyAllowNextNewChar = function (dateFmt, value, evt) {
//keyCodes = [t, T, +, -]
var keyCodes = dateboxAllowedKeyCodes;
var char0 = value.charCodeAt(0) || evt.charCode;
//below block will handles if user enter + or - or t as first character
//if t is the first character, then the user is not allowed enter any character
//if user enters first + or -, then they can enter any number of digits
if (keyCodes.indexOf(char0) >= 0) {
if (value.length != 0) {
if (char0 == 116 || char0 == 84) {
evt.stop();
} else if ((char0 == 45 || char0 == 43) && value.length == 4) {
evt.stop();
} else if (evt.charCode < '0'.charCodeAt(0) || evt.charCode > '9'.charCodeAt(0)) {
evt.stop();
}
}
//below block will ensure user is entering date as per the zone datebox date format
//first block of if case will take care of the cases where the user enters the date as 20211204 and presses tab to get the date in specified format
//the second block of if case will take care of the cases when the user selects date from the picker and the tries to edit the date
} else if ((evt.charCode >= '0'.charCodeAt(0) && evt.charCode <= '9'.charCodeAt(0) && value.length < 8) ||
(((value.includes('-') && evt.charCode >= '0'.charCodeAt(0) && evt.charCode <= '9'.charCodeAt(0)) ||
(evt.charCode === '-'.charCodeAt(0))) && value.length < 10)) {
var dtFmts = parseDateFormatToArr(dateFmt);
var findInputGvn = function (typ) {
var len = typ !== 'y' ? 2 : 4;
for (var i = 0; i <= 6; i += 2) {
if (dtFmts[i].startsWith(typ) && value.length >= i + len) {
return parseInt(value.substr(i, len));
}
}
return null;
}
var expectFmt = dtFmts[value.length];
var prevNum = parseInt(value.substr(-1));
var nxtNum = parseInt(String.fromCharCode(evt.charCode));
var checkDateNextNum = function (yearGvn, monthGvn, evt, d1) {
if (!yearGvn && !monthGvn) {
return;
}
var args = [yearGvn, 0, 0];
if (monthGvn && !d1) {
var date = new Date();
args[1] = monthGvn;
args[0] = args[0] === null ? date.getFullYear() : args[0];
var monthLastDate = (new Date(args[0], args[1], args[2])).getDate();
if (((prevNum * 10) + nxtNum) > monthLastDate) {
evt.stop();
}
} else if (nxtNum > 2) {
evt.stop();
}
}
var validateDate = function (evt) {
if (expectFmt == 'd1' && nxtNum > 3) {
evt.stop();
} else if (expectFmt == 'd2' && prevNum == 0 && nxtNum == 0) {
evt.stop();
} else if (expectFmt == 'd2' && prevNum == 3 && nxtNum > 1) {
evt.stop();
}
//on typing the last date digit, check the date is valid for specific month
//example: if the month is april last date is 30 it will not allow typing 31
if (expectFmt == 'd2' && !evt.stopped) {
var monthGvn = findInputGvn('M');
var yearGvn = findInputGvn('y');
checkDateNextNum(yearGvn, monthGvn, evt);
//below validation only applicable for the feb
//if it feb the date should starts with 2
} else if (expectFmt == 'd1' && !evt.stopped) {
var monthGvn = findInputGvn('M');
if (monthGvn && monthGvn == 2) {
var yearGvn = findInputGvn('y');
checkDateNextNum(yearGvn, monthGvn, evt, true);
}
}
}
var validateMonth = function (evt) {
if (expectFmt == 'M1' && nxtNum > 1) {
evt.stop();
} else if (expectFmt == 'M2' && prevNum == 0 && nxtNum == 0) {
evt.stop();
} else if (expectFmt == 'M2' && prevNum == 1 && nxtNum > 2) {
evt.stop();
}
//if date is entered as 31 then month can't be april
if (expectFmt == 'M2' && !evt.stopped) {
var dateGvn = findInputGvn('d');
var yearGvn = findInputGvn('y');
var args = [yearGvn, 0, 0];
if (dateGvn) {
var date = new Date();
args[1] = ((prevNum * 10) + nxtNum);
args[0] = args[0] === null ? date.getFullYear() : args[0];
var monthLastDate = (new Date(args[0], args[1], args[2])).getDate();
if (dateGvn > monthLastDate) {
evt.stop();
}
}
}
}
var validateYear = function (evt) {
if (expectFmt == 'y4') {
var dateGvn = findInputGvn('d');
var monthGvn = findInputGvn('M');
//this applies only for feb month, if user entered feb 29
//the it will not allows user to enter year which is not having feb 29
if (monthGvn && dateGvn) {
var args = [0, monthGvn, 0];
var last3 = parseInt(value.substr(-3));
args[0] = (last3 * 10) + nxtNum;
var monthLastDate = (new Date(args[0], args[1], args[2])).getDate();
if (dateGvn > monthLastDate) {
evt.stop();
}
}
}
}
if (expectFmt.startsWith('d')) {
validateDate(evt);
} else if (expectFmt.startsWith('M')) {
validateMonth(evt);
} else if (expectFmt.startsWith('y')) {
validateYear(evt);
}
} else {
evt.stop();
}
}
// Overriding validate to force the datebox to fire the update
// When it validates with a correct value and then invalidates, it never sets the input's actual value
// When input's actual value = visible value (the one you see) is the same, it doesn't update the server
zk.override(zul.db.Datebox.prototype, _zDatebox, {
doKeyPress_: function (evt) {
var inp = this.getInputNode();
var value = '' + inp.value;
if (inp.selectionStart == value.length) {
identifyAllowNextNewChar(this.getFormat(), value, evt);
} else {
var sstart = inp.selectionStart > inp.selectionEnd ? inp.selectionEnd : inp.selectionStart;
identifyAllowNextNewChar(this.getFormat(), value.substr(0, sstart), evt);
}
},
doFocus_: function (evt) {
this.rawInputOnFocus();
},
doBlur_: function (evt) {
this.updateRawInput();
this.$supers('doBlur_', arguments);
},
setValue: function (value, fromServer, rawData) {
//this below conditions for the dynamic forms
//rawInput should set to null, whenever new value from server
//this prevents showing un related rawInput values
if (fromServer && this.rawInput !== null) {
this.rawInput = null;
}
//below overridden behaviour will not try to convert the value as date
//converting to date will happen in original setValue
if (!fromServer && rawData) {
this.clearErrorMessage(false);
this.$class._clearOnChanging(this);
var inp = this.getInputNode();
if (inp) {
this._defRawVal = this._lastChg = inp.value = value;
}
//invoke the original setValue
} else {
this.$supers('setValue', arguments);
}
},
updateRawInput: function () {
var value = this.getInputNode().value, char0 = value.charCodeAt(0) || -1;
//check the input is raw input or value given by date picker
//below condition prevents always changing the value while on focus
if (dateboxAllowedKeyCodes.indexOf(char0) >= 0 || value.match('^[0-9]+$')) {
this.rawInput = value;
}
},
overridePopOnChange: function (evt) {
//user picked date through picker, forgot about the previous typed value
this.rawInput = null;
//invoke the original onChange method, will update the changes
this.$popinit(evt);
},
rawInputOnFocus: function () {
//if user picks date through date picker, we should update the rawInput if not
//after picking the date, the non updated rawInput value will be shown instead of picked date
//we don't have any option in overriding the zul.dp.CalanderPop.onChange method, below is the shortcut for overriding
if (!this.$popinit) {
this.$popinit = new $callback(this._pop, this._pop.onChange);
this._pop.onChange = new $callback(this, this.overridePopOnChange);
}
if (this.rawInput) {
this.setValue(this.rawInput, false, true);
this.select();
}
}
});
});