如何使用Dojo的DatePicker控件製作聯動日期選擇器

在開發系統的調查功能時,需要設計一個可以聯動的開始日期/結束日期選擇器用來設定用戶的調查的起始/結束日期。對於這個聯動的日期選擇器,我們的設計要求是這樣的:

在新增調查時,該調查的開始日期默認爲今天,而結束日期則不能選擇成今天之前的日期;
當用戶修改開始日期時,將判斷當前用戶設定的結束日期,如果結束日期在修改後的開始日期之後,則不修改結束日期,而如果結束日期變成了在修改後的開始日期之前時,則修改結束日期,和開始日期爲同一天,並且設定用戶不能選擇開始日期之前的日期爲結束日期;
修改結束日期時,不能選擇開始日期之前的日期。

針對這樣的要求,決定使用dojo的日期選擇控件 DatePicker / DropDownDatePicker 來實現。

 

最終的效果,聯動的DatePicker,注意20日之前的日期都是不能選擇的


針對第1和第3點要求,dojo的 DatePicker / DropDownDatePicker 可以輕易的實現,可以通過設置 DatePicker / DropDownDatePicker 的 value 和startDate這兩個屬性實現。而要這個需求的難點在於兩個DatePicker之間的聯動,也就是說,要動態的根據第一個DatePicker的值來設定第二個DatePicker的startDate屬性。但是不幸的是,dojo沒有提供直接的動態修改 DatePicker 的 startDate / endDate 的方法。雖然我們可以隨時修改DatePicker的startDate屬性,但是,在UI(日期選擇界面)卻不會發生變化,達不到我們想要的效果。

dojo提供了一個onValueChanged的事件,我們可以爲第一個DatePicker添加這個事件的觸發器,觸發後調用我們自己寫的 Javascript函數。而在這個函數裏我們要解決的問題就只有修改第二個DatePicker的startDate屬性(這個很簡單),並讓UI即時生效(問題就在這裏)了。

在仔細研究了dojo的DatePicker的源代碼後發現,startDate僅僅是這個 DatePicker控件的一個單純的屬性,修改它並不會在內部觸發任何改動UI的事件。所以,我們要做的就變得很簡單了——想辦法重繪UI就可以。不幸中的萬幸是,我們找到了_preInitUI()這個內部的方法,它可以繪製DatePicker的UI。

一切明朗後,就變得很簡單了。看看代碼片斷吧,很輕鬆的實現了兩個DatePicker / DropDownDatePicker控件的聯動。

HTML4STRICT代碼:

開始時間:<input dojoType="dropdowndatepicker" id="startdate" name="start" value="today" displayFormat="yyyy-MM-dd" onValueChanged="checkEndDate" />
    結束時間:<input dojoType="dropdowndatepicker" id="enddate" name="end" displayFormat="yyyy-MM-dd" />


注意看上面HTML代碼中的第一個DropDownDatePicker控件的屬性:

value設置爲today則會默認帶出今天的日期
displayFormat設置時間顯示格式(便於後臺程序轉換成timestamp導入DB)
onValueChanged則設置了觸發名爲checkEndDate的自定義Javascript函數
再看看Javascript代碼片斷:

JAVASCRIPT代碼:

function g(id) {
    return document.getElementById(id);
}
function w(id) {
    return dojo.widget.getWidgetById(id);
}
function checkEndDate(){
    var func=function(){
        //得到新的修改後的開始日期和當前的結束日期
        starttime=w('startdate').getDate();
        endtime=w('enddate').getDate();
        //開始日期是否在結束日期之後?
        if (starttime>endtime) {
             //開始日期在結束日期之後,修改結束日期等於開始日期
            w('enddate').setDate(starttime); //時間戳
            w('enddate').value=w('startdate').inputNode.value; //字符串值
        }
        //設定結束日期的startDate屬性,限制用戶選擇開始日期之前的日期
        var startDate=dojo.date.fromRfc3339(w('startdate').inputNode.value).setHours(0,0,0,0);
        w('enddate').startDate=w('startdate').inputNode.value;
        w('enddate').datePicker.startDate=startDate;
        //得到結束日期的當前月份
        var d = new Date(w('enddate').datePicker.curMonth);
        //利用_preInitUI()重繪結束日期的UI(當前月)
        w('enddate').datePicker._preInitUI(d,false,true);
    }
    //延時500毫秒執行
    window.setTimeout(func,500);
}


怎麼樣,很簡單吧?不過你也許要問,爲什麼要延時500毫秒執行呢?原因是這樣的,一開始瀏覽器在繪製頁面的時候,設定開始日期爲今天,這一動作同樣會觸發 onValueChanged事件。但這時候,因爲結束日期的DatePicker控件還未被瀏覽器繪製完成,所以導致觸發onValueChanged 事件後,Javascript無法執行成功,根本get不到enddate這個element。所以,我採取了onValueChanged事件觸發後 500毫秒後執行Javascript程序,這時候,再慢的電腦都已經render完這個element了,執行Javascript就不會出錯了,而且對於用戶,也沒什麼感覺。當然,你也可以寫一個onLoad事件的Javascript函數在頁面加載完成後再給startdate這個element賦值。這都是問題的解決辦法,怎麼使用完全取決於你。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章