2014年8月12日 星期二

ASP.NET MVC - 下拉選單的日期選擇器 Part.1

以往都會一直強調在表單的日期輸入應該要使用日期選擇器(DatePicker),而避免直接使用一般的文字輸入框來讓使用者直接輸入日期,為了要避免輸入格式的紊亂之外,最重要的還是要確保使用者所輸入的日期是正確的,例如現在常常會看到許多人使用的「bootstrap-datepicker」,或者是在以前有曾經介紹過的「My97 DatePicker」,雖然說 Chrome 有支援 HTML 5 的日期格式,讓使用者輸入日期時就有 DatePicker 可以讓使用者使用,不過目前大部分的瀏覽器還沒有提供支援。

image

如果客戶不希望使用 DatePicker ,而是想要使用下拉選單來選擇年月日的方式輸入日期的話,也是可以的,這並非難事,有些人會選擇自己做,而也有很多人會直接到網路上尋找是否有符合功能需求的現有 jQuery Plugins。

這篇就來說明如何在 ASP.NET MVC 的專案裡去使用下拉選單的日期選擇器,另外也可以將年份選則由西元年改以民國年來顯示。

 


因為現在的 ASP.NET MVC 5 的專案範本是使用 Bootstrap,所以許多人在日期輸入的部分就會使用「bootstrap-datepicker」這類的日期選擇器,

image

或者是在以前有曾經介紹過的「My97 DatePicker

image

 

如果是需要改用下拉選單的方式來選擇日期的話,有些人做得比較簡單(隨便?)在頁面上放三個下拉選單,年的部分就直接給 100 個年的項目,月份就給 12 個月份的項目,而日期的部分就是直接放 31 個日期選項,所以當選擇年度、月份的時候並不會改變日期的項目,所以輸入的資料就必須仰賴後端程式的驗證。

不過一般的客戶都應該不會接受這麼簡單的作法,通常都會要求前端就必須要讓使用者能夠選擇到「正確的日期」,這麼一來要考慮的事情就會稍微多一點,選擇不同的月份就要連動改變日期部分的選項,而潤年也必須考慮到選擇二月時的日期是有 29 天,另外要考慮的事情還不只這些, 所以我會選擇直接使用別人已經寫好的套件。

再來就是我希望可以讓我們可以將年的部分由西元年改成使用民國年來顯示,然後可以在 ASP.NET MVC 裡的使用,甚至也可以改為 Editor Template 的方式來使用,所以就必須選擇一個讓我比較好改的現有套件;其實現在有很多現成套件都做得很好也相當好用,但是都不太好改,最後我就選擇了「Date Drop Down Lists」這個套件為基礎然後再來做修改。

Date Drop Down Lists | Things | Alan Donnelly - .Net Web Developer Glasgow

https://github.com/amdonnelly/jQuery-Date-List-Plugin

image

原版的功能是相當基本的,可以自訂日期格式,月份可以選擇顯示文字或日期,另外可以設定起迄年度,但是我想要再增加兩個功能,一個就是前面有說過的「顯示民國年」,另一個就是讓開發人員決定是否增加三個下拉選單的第一個 Option 與顯示文字,另外還有一個小修改就是年度的項目是由大到小的降冪排序。

 

修改後的內容

以下是我修改過後的內容,程式內容與原本的程式有蠻大的不同了,

jquery.dateLists.dev.js

;
(function ($) {
    $.fn.dateDropDowns = function (options) {
 
        var defaults = {
            dateFormat: 'dd-mm-yy',
            monthNames: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
            yearStart: ((new Date()).getFullYear() - 100).toString(), yearEnd: (new Date()).getFullYear().toString(),
            taiwanCalendarYear: false,
            yearOption: '',
            monthOption: '',
            dayOption: ''
        };
        var options = $.extend(defaults, options);
 
        return this.each(function () {
            var obj = $(this);
            var body = obj.html();
 
            var _container_name = obj.attr('id') + '_dateLists';
            var _container_name_day = _container_name + '_day';
            var _container_name_month = _container_name + '_month';
            var _container_name_year = _container_name + '_year';
 
            var _startDate = obj.val();
            var _date = new Date();
            var _seperator = (defaults.dateFormat.indexOf('/') > -1) ? '/' : '-';
 
            GetStartDate();
            AddLists();
            PopulateLists();
            SetupChangeHandlers();
 
            //=========================================================================
            function GetStartDate() {
                if (_startDate.length > 0) {
                    var _dateSections = defaults.dateFormat.split(_seperator);
                    var _dateParts = _startDate.split(_seperator);
                    var _newDate = new Date();
 
                    for (_x = 0; _x < _dateParts.length; _x++) {
                        if (_dateSections[_x].toLowerCase().indexOf('d') > -1) {
                            _newDate.setDate(_dateParts[_x]);
                        }
                        else if (_dateSections[_x].toLowerCase().indexOf('m') > -1) {
                            _newDate.setMonth(_dateParts[_x] - 1);
                        }
                        else if (_dateSections[_x].toLowerCase().indexOf('y') > -1) {
                            _newDate.setYear(_dateParts[_x]);
                        }
                    }
 
                    _date = _newDate;
                }
            }
 
            //=========================================================================
            function AddLists() {
                var _dateSections = defaults.dateFormat.split(_seperator);
 
                var _obj = obj;
                obj.replaceWith('<div id="' + _container_name + '"></div>');
 
                var $targetElement = $('#' + _container_name);
 
                for (_x = 0; _x < _dateSections.length; _x++) {
 
                    if (_dateSections[_x].toLowerCase().indexOf('d') > -1) {
                        $('<select></select>')
                            .attr({
                                'id': _container_name_day + '_list',
                                'name': _container_name_day + '_list',
                                'style': 'margin: 5px;'
                            })
                            .appendTo($targetElement);
                    }
                    else if (_dateSections[_x].toLowerCase().indexOf('m') > -1) {
                        $('<select></select>')
                            .attr({
                                'id': _container_name_month + '_list',
                                'name': _container_name_month + '_list',
                                'style': 'margin: 5px;'
                            })
                            .appendTo($targetElement);
                    }
                    else if (_dateSections[_x].toLowerCase().indexOf('y') > -1) {
                        $('<select></select>')
                            .attr({
                                'id': _container_name_year + '_list',
                                'name': _container_name_year + '_list',
                                'style': 'margin: 5px;'
                            })
                            .appendTo($targetElement);
                    }
                }
 
                $targetElement.append(_obj);
                obj.hide();
            }
 
            //=========================================================================
 
            function PopulateLists() {
                PopulateDayList();
                PopulateMonthList();
                PopulateYearList();
            }
 
            function PopulateDayList() {
                /// <summary>
                /// Populate Day List
                /// </summary>
 
                var _currentMonth = _date.getMonth() + 1;
                var _start = 1;
 
                _daysInMonth = GetMonthDays(_currentMonth, _date.getFullYear()) + 1;
 
                var $targetElement = $('#' + _container_name_day + '_list');
                var selectedDay = $targetElement.val();
 
                $targetElement.children().remove();
                $('<option></option>')
                    .attr('value', '').text(defaults.dayOption)
                    .appendTo($targetElement);
 
                for (_x = _start; _x < _daysInMonth; _x++) {
                    var _selected = _startDate.length > 0
                        ? (_date.getDate() == _x) ? 'selected="true"' : ''
                        : '';
 
                    $('<option ' + _selected + '></option>')
                        .attr('value', _x).text(_x).appendTo($targetElement);
                }
 
                if (selectedDay) {
                    var isOptionExists = $targetElement.find('option[value=' + selectedDay + ']').length > 0;
                    $targetElement.val(isOptionExists ? selectedDay : '');
                }
            }
 
            function GetMonthDays(prmMonth, prmYear) {
                /// <summary>
                /// Get the number of days for a given month
                /// </summary>
                /// <param name="prmMonth"></param>
                /// <param name="prmYear"></param>
                /// <returns type=""></returns>
 
                var _daysInMonth = 31;
 
                if (prmMonth == 4 || prmMonth == 6 || prmMonth == 9 || prmMonth == 11) {
                    _daysInMonth = 30;
                }
                else if (prmMonth == 2) {
                    _daysInMonth = (prmYear % 4) == 0 ? 29 : 28;
                }
                return _daysInMonth;
            }
 
            function PopulateMonthList() {
                /// <summary>
                /// Populate Month List
                /// </summary>
 
                var $targetElement = $('#' + _container_name_month + '_list');
                $targetElement.children().remove();
                $('<option></option>')
                    .attr('value', '').text(defaults.monthOption)
                    .appendTo($targetElement);
 
                for (_x = 0; _x < 12; _x++) {
                    var _selected = _startDate.length > 0
                        ? ((_date.getMonth()) == _x) ? 'selected="true"' : ''
                        : '';
 
                    $('<option ' + _selected + '></option>')
                        .attr('value', _x)
                        .text(defaults.monthNames[_x])
                        .appendTo($targetElement);
                }
            }
 
            function PopulateYearList() {
                /// <summary>
                /// Populate Year List
                /// </summary>
 
                var $targetElement = $('#' + _container_name_year + '_list');
 
                $targetElement.children().remove();
 
                $('<option></option>')
                    .attr('value', '').text(defaults.yearOption)
                    .appendTo($targetElement);
 
                var _yStart = parseInt(defaults.yearStart, 10);
                var _yEnd = parseInt(defaults.yearEnd, 10);
 
                if (_yEnd < _yStart) {
                    var temp = _yStart;
                    _yStart = _yEnd;
                    _yEnd = temp;
                }
 
                for (_x = _yEnd; _x >= _yStart; _x--) {
                    var _selected = _startDate.length > 0
                        ? ((_date.getFullYear()) == _x) ? 'selected="true"' : ''
                        : '';
 
                    $('<option ' + _selected + '></option>')
                        .attr('value', _x)
                        .text(defaults.taiwanCalendarYear ? _x - 1911 : _x)
                        .appendTo($targetElement);
                }
            }
 
            //=========================================================================   
 
            function SetupChangeHandlers() {
 
                var $daySelect = $('#' + _container_name_day + '_list');
                var $monthSelect = $('#' + _container_name_month + '_list');
                var $yearSelect = $('#' + _container_name_year + '_list');
 
                $daySelect.change(function () {
                    _date.setDate($daySelect.val());
                    CreateDate();
                });
 
                $monthSelect.change(function () {
                    var _newMonth = parseInt($monthSelect.val(), 10);
                    var _days = _date.getDate();
 
                    _daysInMonth = GetMonthDays(_newMonth + 1, _date.getFullYear());
 
                    if (_days > _daysInMonth) {
                        _days = _daysInMonth;
                    }
 
                    var _newDate = new Date(_date.getFullYear(), _newMonth, _days, 0, 0, 0, 0);
                    _date = _newDate;
 
                    PopulateDayList();
                    CreateDate();
                });
 
                $yearSelect.change(function () {
                    var _newYear = $yearSelect.val();
                    var _days = _date.getDate();
                    var _month = _date.getMonth();
 
                    _daysInMonth = GetMonthDays(_month + 1, _newYear);
 
                    if (_days > _daysInMonth) {
                        _days = _daysInMonth;
                    }
 
                    var _newDate = new Date(_newYear, _month, _days, 0, 0, 0, 0);
 
                    _date = _newDate;
 
                    PopulateDayList();
                    CreateDate();
                });
            }
 
            function CreateDate() {
                var _days = _date.getDate();
                var _month = _date.getMonth() + 1;
                var _year = _date.getFullYear();
 
                var _dateFormat = defaults.dateFormat;
 
                if (_dateFormat.indexOf('DD') > -1 && _days.toString().length < 2) {
                    _days = '0' + _days;
                }
                if (_dateFormat.indexOf('MM') > -1 && _month.toString().length < 2) {
                    _month = '0' + _month;
                }
 
                var _newDate = defaults.dateFormat.toLowerCase();
                _newDate = _newDate.replace('dd', _days);
                _newDate = _newDate.replace('mm', _month);
                _newDate = _newDate.replace('yy', _year);
 
                obj.val(_newDate);
            }
        });
    };
})(jQuery);


基本的使用

image

image

 

簡單的變化使用

image

要將 SelectDate 這一個 text 輸入項轉換為下拉式的日期選擇器,使用以下的設定,

image

顯示結果

image

image

 

設定預設值以及使用民國年顯示

image

image

 

這一篇就先說明到這裡,下一篇來說明 ASP.NET MVC 內的一般使用方式。

 

系列文章:

ASP.NET MVC - 下拉選單的日期選擇器 Part.1

ASP.NET MVC - 下拉選單的日期選擇器 Part.2

ASP.NET MVC - 下拉選單的日期選擇器 Part.3 - Editor Templates

ASP.NET MVC - 下拉選單的日期選擇器 Part.4 - Editor Templates

ASP.NET MVC - 下拉選單的日期選擇器 Part.5 - Editor Templates

ASP.NET MVC - 下拉選單的日期選擇器 Part.6 - @helper ?

ASP.NET MVC - 下拉選單的日期選擇器 part.7 - Validation

 

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。

最近的留言