markdown
#背景
當grid使用server端做分頁排序篩選時,查詢的邏輯就是靠`ToDataSourceResult`來控制,
所以改不了內容在幹嘛,
當前端Grid需要篩選某日期欄位,該欄位又有時分秒,且使用者不想設定秒數時,
預設的時間篩選欄位只會傳入年月日到後端,時分秒為零,
但這樣在做小於等於或者等於的查詢時就會遇到時分秒不相同而查不到資料的問題,
如果是自己做api,這種小地方可以調整用`System.Data.Entity.DbFunctions.TruncateTime()`來過濾時間,但用Telerik的類別處理時就不行了,
後來查到官方的解法如連結
https://docs.telerik.com/kendo-ui/controls/data-management/grid/how-to/filtering/filter-by-date
大致上就是說要在filter menu初始化時,複寫套用的按鈕的事件,
例如原本設"等於"條件時,只會傳入一個邏輯就是相等一個日期時間值,
我們要調整為兩個邏輯,
用大於等於當天的零點零分零秒與 小於等於當天的23點59分59秒兩個條件傳入後端,
這樣就可以避免對不上時間的問題了
```
filterMenuInit: function (e) {
//當日期條件設定為小於/等於時 只會傳入年月日 不會傳入時分秒
//但這樣會撈不到當天0點之後的資料 所以要幫他加到23:59:59來方便處理
//(因為沒辦法調整語法為trunc time)
var menu = $(e.container);
if (e.field === "ColumnDateTime") {
var firstDropDown = $('[data-bind="value: filters[0].operator"]').data('kendoDropDownList');
menu.find('button[type="submit"]').click(function (ev) {
if (firstDropDown.value() === 'eq') {
ev.preventDefault();
var selectedDate = menu.find('[data-role="datepicker"]').first().data('kendoDatePicker').value();
if (!selectedDate) {
$(ev.target).closest('[data-role="popup"]').data('kendoPopup').close();
return;
}
var startOfFilterDate = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());
var endOfFilterDate = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate(), 23, 59, 59);
var filter = {
logic: "and",
filters: [
{ field: "ColumnDateTime", operator: "gte", value: startOfFilterDate },
{ field: "ColumnDateTime", operator: "lte", value: endOfFilterDate }
]
};
e.sender.dataSource.filter(filter);
$(ev.target).closest('[data-role="popup"]').data('kendoPopup').close();
return;
} else if (firstDropDown.value() === 'le') {
ev.preventDefault();
var selectedDate = menu.find('[data-role="datepicker"]').first().data('kendoDatePicker').value();
if (!selectedDate) {
$(ev.target).closest('[data-role="popup"]').data('kendoPopup').close();
return;
}
var endOfFilterDate = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate(), 23, 59, 59);
var filter = {
logic: "and",
filters: [
{ field: "ColumnDateTime", operator: "lte", value: endOfFilterDate }
]
};
e.sender.dataSource.filter(filter);
$(ev.target).closest('[data-role="popup"]').data('kendoPopup').close();
return;
}
});
}
},
```
2018年1月25日 星期四
2017年12月8日 星期五
Kendo UI Date Picker 民國年格式 | Kendo UI Date Picker Taiwan calander format
markdown
#背景
一個Grid,在編輯時用popup,內容是template,
有個日期欄位,
使用者想要輸入1060101或者10601011735這種日期或日期時間格式
不想要選取也不想要打「-」、空白或「:」
研究了一下也提問在官方討論區了,官方是說不支援民國年這種格式,
實際上你輸入1900年之前的日期,也會無法set,
所以也不能用民國106年直接套上DatePicker/DateTimePicker,而且萬年曆也會不對,
這裡就用textbox自幹一個字串轉日期的方法
(如果想要讓後端收到的值仍然有「-」、空白或「:」,是可以搭配mask)
首先在原本的template的時間輸入框前面加入一個input textbox
```
```
然後準備好字串轉日期、日期轉字串的處理,
這裡列的方法是我很直觀的去寫,沒有做什麼效能分析
```
//傳入值與格式,分析與轉換成JS日期物件 function parseTWDate(val, format) { var result = { result: true, msg: "", DateObj: null }; if (typeof val === "undefined") { result.result = false; return result; } //只接受數字與字串型態 if (typeof val !== "number" && typeof val !== "string") { result.result = false; return result; } //檢查格式字串 if ( format !== "yyyMMdd" && format !== "yyyMMddHHmm" && format !== "yyyMMddHHmmss" ) { result.result = false; result.msg = "不支援的日期格式設定"; return result; } //只接受數字不接受符號 if (/^\d+$/.test(val) === false) { result.result = false; return result; } var str = ""; //數字型態轉文字 if (typeof val === "number") { str = val.toString(); } else { str = val; } //從後往前兩位兩位取出字串,轉數字後做驗證 var sec = 0; var min = 0; var hr = 0; var day = 0; var mon = 0; var year = 0; var movingCount = 0; if (format === "yyyMMddHHmmss") { if (str.length < 11) { result.result = false; return result; } sec = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (sec === NaN || sec > 59 || sec < 0) { result.result = false; return result; } movingCount += 2; } if (format === "yyyMMddHHmm" || format === "yyyMMddHHmmss") { if (str.length < 9) { result.result = false; return result; } min = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (min === NaN || min > 59 || min < 0) { result.result = false; return result; } movingCount += 2; hr = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (hr === NaN || hr > 23 || hr < 0) { result.result = false; return result; } movingCount += 2; } if (str.length < 5) { result.result = false; return result; } day = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (day === NaN || day > 31 || day < 1) { result.result = false; return result; } movingCount += 2; mon = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (mon === NaN || mon > 12 || mon < 1) { result.result = false; return result; } movingCount += 2; year = parseInt(str.substring(0, str.length - movingCount), 10); if (year === NaN || year < 1) { result.result = false; return result; } //JS的日期的月份是0 base result.DateObj = new Date(year + 1911, mon - 1, day, hr, min, sec); return result; } //將日期選擇轉成民國年 function getTWDate(val, format) { var rawYear = val.getFullYear(); var twYear = rawYear - 1911; var rawMonth = val.getMonth() + 1; var twMonth = rawMonth.toString().padStart(2, "0"); var rawDay = val.getDate(); var twDay = rawDay.toString().padStart(2, "0"); var strTWDate = twYear + twMonth + twDay; if (format === "yyyMMddHHmm" || format === "yyyMMddHHmmss") { var hr = val .getHours() .toString() .padStart(2, "0"); var min = val .getMinutes() .toString() .padStart(2, "0"); strTWDate = strTWDate + hr + min; if (format === "yyyMMddHHmmss") { var sec = val .getSeconds() .toString() .padStart(2, "0"); strTWDate = strTWDate + sec; } } return strTWDate; } ```
然後在原本的datasource的schema中加入一個自訂的民國年欄位,類型是字串
這個欄位不會回傳值給API,只是用來data bind,
裡面做自定義驗證方法,在民國年字串輸入框跳開時,去跑日期解析,
成功就把日期物件帶回model,失敗就給予錯誤訊息並回傳false;
原本的欄位也給他一個驗證是如果跑到了驗證就檢查他的值是否可以解析成日期,
這裡弄了很久是不知如何避免偶爾會出現原欄位跳出必填的問題,
還有編輯時無法透過model.set讓他自己data bind去改變前端DOM的值,
set下去model的值竟然不會改,只能手動去塞值&改DOM,
改值的時候也要先改DOM在做SET,不然也會有怪現象
```
var dataSource = { schema: { model: { fields: { myDate: { type: "date", validation: { required: true, dateFormat: function(input, option) { if (input.is("[name='myDate']")) { if (Date.parse(input.val()) !== NaN) { $("#myDateTW").removeAttr("data-TWdate-msg"); $("#myDate").removeAttr("data-required-msg"); return true; } else { $("#myDateTW").attr( "data-TWdate-msg", "格式民國年yyyMMdd" ); return false; } } else { return true; } } } }, myDateTW: { type: "string", validation: { required: true, TWdate: function(input, option) { if (input.is("[name='myDateTW']")) { var val = input.val(); var format = "yyyMMdd"; var result = parseTWDate(val, format); if (result.result) { input.removeAttr("data-TWdate-msg"); //帶回model var source = $("#myDateTW")[0].kendoBindingTarget .source; $("#myDate").val(result.DateObj); source.set("myDate", result.DateObj); return true; } else { input.attr("data-TWdate-msg", "格式民國年" + format); //帶回model var source = $("#myDateTW")[0].kendoBindingTarget .source; $("#myDate").val(val); source.set("myDate", val); return false; } } else { return true; } } }, } } } }, }; }; ```
再來是grid新增或編輯時需要把model的date欄位清空與轉換
```
edit: function(e) { var arg = e; if (e.model.isNew()) { //日期型態先清空 e.model.set("myDate", null); } else { //民國年要先轉好 var myDate = e.model.get("ㄗㄩDate"); var strMyDateTW = getTWDate(myDate, "yyyMMdd"); e.model.myDateTW = strMyDateTW; e.model.set("myDateTW", strMyDateTW); $("#myDateTW").val(strMyDateTW); } } ```
這樣就可以輸入民國年日期轉成西元年日期,編輯時也可以把西元年日期轉回民國年日期了
#背景
一個Grid,在編輯時用popup,內容是template,
有個日期欄位,
使用者想要輸入1060101或者10601011735這種日期或日期時間格式
不想要選取也不想要打「-」、空白或「:」
研究了一下也提問在官方討論區了,官方是說不支援民國年這種格式,
實際上你輸入1900年之前的日期,也會無法set,
所以也不能用民國106年直接套上DatePicker/DateTimePicker,而且萬年曆也會不對,
這裡就用textbox自幹一個字串轉日期的方法
(如果想要讓後端收到的值仍然有「-」、空白或「:」,是可以搭配mask)
首先在原本的template的時間輸入框前面加入一個input textbox
```
```
然後準備好字串轉日期、日期轉字串的處理,
這裡列的方法是我很直觀的去寫,沒有做什麼效能分析
```
//傳入值與格式,分析與轉換成JS日期物件 function parseTWDate(val, format) { var result = { result: true, msg: "", DateObj: null }; if (typeof val === "undefined") { result.result = false; return result; } //只接受數字與字串型態 if (typeof val !== "number" && typeof val !== "string") { result.result = false; return result; } //檢查格式字串 if ( format !== "yyyMMdd" && format !== "yyyMMddHHmm" && format !== "yyyMMddHHmmss" ) { result.result = false; result.msg = "不支援的日期格式設定"; return result; } //只接受數字不接受符號 if (/^\d+$/.test(val) === false) { result.result = false; return result; } var str = ""; //數字型態轉文字 if (typeof val === "number") { str = val.toString(); } else { str = val; } //從後往前兩位兩位取出字串,轉數字後做驗證 var sec = 0; var min = 0; var hr = 0; var day = 0; var mon = 0; var year = 0; var movingCount = 0; if (format === "yyyMMddHHmmss") { if (str.length < 11) { result.result = false; return result; } sec = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (sec === NaN || sec > 59 || sec < 0) { result.result = false; return result; } movingCount += 2; } if (format === "yyyMMddHHmm" || format === "yyyMMddHHmmss") { if (str.length < 9) { result.result = false; return result; } min = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (min === NaN || min > 59 || min < 0) { result.result = false; return result; } movingCount += 2; hr = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (hr === NaN || hr > 23 || hr < 0) { result.result = false; return result; } movingCount += 2; } if (str.length < 5) { result.result = false; return result; } day = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (day === NaN || day > 31 || day < 1) { result.result = false; return result; } movingCount += 2; mon = parseInt( str.substring(str.length - movingCount - 2, str.length - movingCount), 10 ); if (mon === NaN || mon > 12 || mon < 1) { result.result = false; return result; } movingCount += 2; year = parseInt(str.substring(0, str.length - movingCount), 10); if (year === NaN || year < 1) { result.result = false; return result; } //JS的日期的月份是0 base result.DateObj = new Date(year + 1911, mon - 1, day, hr, min, sec); return result; } //將日期選擇轉成民國年 function getTWDate(val, format) { var rawYear = val.getFullYear(); var twYear = rawYear - 1911; var rawMonth = val.getMonth() + 1; var twMonth = rawMonth.toString().padStart(2, "0"); var rawDay = val.getDate(); var twDay = rawDay.toString().padStart(2, "0"); var strTWDate = twYear + twMonth + twDay; if (format === "yyyMMddHHmm" || format === "yyyMMddHHmmss") { var hr = val .getHours() .toString() .padStart(2, "0"); var min = val .getMinutes() .toString() .padStart(2, "0"); strTWDate = strTWDate + hr + min; if (format === "yyyMMddHHmmss") { var sec = val .getSeconds() .toString() .padStart(2, "0"); strTWDate = strTWDate + sec; } } return strTWDate; } ```
然後在原本的datasource的schema中加入一個自訂的民國年欄位,類型是字串
這個欄位不會回傳值給API,只是用來data bind,
裡面做自定義驗證方法,在民國年字串輸入框跳開時,去跑日期解析,
成功就把日期物件帶回model,失敗就給予錯誤訊息並回傳false;
原本的欄位也給他一個驗證是如果跑到了驗證就檢查他的值是否可以解析成日期,
這裡弄了很久是不知如何避免偶爾會出現原欄位跳出必填的問題,
還有編輯時無法透過model.set讓他自己data bind去改變前端DOM的值,
set下去model的值竟然不會改,只能手動去塞值&改DOM,
改值的時候也要先改DOM在做SET,不然也會有怪現象
```
var dataSource = { schema: { model: { fields: { myDate: { type: "date", validation: { required: true, dateFormat: function(input, option) { if (input.is("[name='myDate']")) { if (Date.parse(input.val()) !== NaN) { $("#myDateTW").removeAttr("data-TWdate-msg"); $("#myDate").removeAttr("data-required-msg"); return true; } else { $("#myDateTW").attr( "data-TWdate-msg", "格式民國年yyyMMdd" ); return false; } } else { return true; } } } }, myDateTW: { type: "string", validation: { required: true, TWdate: function(input, option) { if (input.is("[name='myDateTW']")) { var val = input.val(); var format = "yyyMMdd"; var result = parseTWDate(val, format); if (result.result) { input.removeAttr("data-TWdate-msg"); //帶回model var source = $("#myDateTW")[0].kendoBindingTarget .source; $("#myDate").val(result.DateObj); source.set("myDate", result.DateObj); return true; } else { input.attr("data-TWdate-msg", "格式民國年" + format); //帶回model var source = $("#myDateTW")[0].kendoBindingTarget .source; $("#myDate").val(val); source.set("myDate", val); return false; } } else { return true; } } }, } } } }, }; }; ```
再來是grid新增或編輯時需要把model的date欄位清空與轉換
```
edit: function(e) { var arg = e; if (e.model.isNew()) { //日期型態先清空 e.model.set("myDate", null); } else { //民國年要先轉好 var myDate = e.model.get("ㄗㄩDate"); var strMyDateTW = getTWDate(myDate, "yyyMMdd"); e.model.myDateTW = strMyDateTW; e.model.set("myDateTW", strMyDateTW); $("#myDateTW").val(strMyDateTW); } } ```
這樣就可以輸入民國年日期轉成西元年日期,編輯時也可以把西元年日期轉回民國年日期了
訂閱:
文章 (Atom)