ASP.NET MVC - DatePicker 日期選擇器 | (1) jQuery UI : DatePicker

jQuery UI : DatePicker

表單第四篇,我們來終於來到日期選擇器(DataPicker)。

在表單上最容易產生的錯誤就是「輸入錯誤」,例如,我們網站裡的客戶註冊資料,明明就已經設計電子郵件必須輸入兩次,而且兩次必須完全相同才能通過驗證,還是會有客戶發 Mail 來說:「對不起,我 Email 輸入錯誤,請幫我修正資料。」一整個 Orz!

所以能「勾勾、選選」是最好的選擇,最少能減低這類的「輸入錯誤」。其中「日期」的輸入通常都是很重要,註冊日期、購買日期、出貨日期、銷售日期、保固日期、發佈日期、LogOn-LogOut日期…等。

前面介紹的 HTML 編輯器,是美化你輸入的資料。有時"日期"就重要性而言,會比內容更為重要。我們希望減少日期的輸入錯誤,但一個字一個字打,日期的錯誤率就硬是比Email這類資料還高。

所以就出現「用選的」這類需求。就有人開發出 DatePicker,讓使用者可以很方便,用選的,幾年幾月幾日,一整個就是爽。不管是 UI、Usability … DatePicker 與 HTML Editor 都是加分部分。

前面準備一樣,Model、Controller \ Action、View。

Model:BlogPostjQueryUI.vb

Imports System.ComponentModel.DataAnnotations

''' <summary>
''' Blog 發佈文章類別
''' </summary>
Public Class BlogPostjQueryUI
    ' 標題
    Public Property Title() As String
    ' 發佈日期
    <DataType(DataType.Date)>
    Public Property PostedOn() As DateTime
    ' 標籤
    Public Property Tags() As String
    ' 內容
    Public Property Content() As String
End Class

Controller \ Action:BlogPostjQueryUIController.vb

Namespace Mvc3HTMLEditorAndDatePicker
    Public Class BlogPostjQueryUIController
        Inherits System.Web.Mvc.Controller

        '
        ' GET: /BlogPostjQueryUI/Create

        Function Create() As ActionResult
            Return View()
        End Function

        <HttpPost(), ActionName("Create")>
        Function Create_Post(model As BlogPostjQueryUI) As ActionResult
            ViewBag.HtmlContent = model.Content
            Return View(model)
        End Function

    End Class
End Namespace

建置,用強型別新增View。

View:Create.aspx

<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of Mvc3HTMLEditorAndDatePicker.BlogPostjQueryUI)" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    KKBruce : DatePicker (使用jQuery UI) 日期選擇器測試
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>DatePicker (使用jQuery UI) 日期選擇器測試</h2>

<%-- The following line works around an ASP.NET compiler warning --%>
<%: "" %>

<script src="<%: Url.Content("~/Scripts/jquery.validate.min.js") %>" type="text/javascript"></script>
<script src="<%: Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js") %>" type="text/javascript"></script>

<% Using Html.BeginForm() %>
    <%: Html.ValidationSummary(True) %>
    <fieldset>
        <legend>jQuery UI 日期選擇器測試</legend>

        <div class="editor-label">
            <%: Html.LabelFor(Function(model) model.Title) %>
        </div>
        <div class="editor-field">
            <%: Html.EditorFor(Function(model) model.Title) %>
            <%: Html.ValidationMessageFor(Function(model) model.Title) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(Function(model) model.PostedOn) %>
        </div>
        <div class="editor-field">
            <%: Html.EditorFor(Function(model) model.PostedOn) %>
            <%: Html.ValidationMessageFor(Function(model) model.PostedOn) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(Function(model) model.Tags) %>
        </div>
        <div class="editor-field">
            <%: Html.EditorFor(Function(model) model.Tags) %>
            <%: Html.ValidationMessageFor(Function(model) model.Tags) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(Function(model) model.Content) %>
        </div>
        <div class="editor-field">
            <%: Html.EditorFor(Function(model) model.Content) %>
            <%: Html.ValidationMessageFor(Function(model) model.Content) %>
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
<% End Using %>

<div>
    <%: Html.ActionLink("回首頁", "Index", "Home") %>
</div>

</asp:Content>

日期選擇器( DatePicker ) 第一個我們來介紹最簡易入門的 jQuery UI。

設定與使用 jQuery UI - DatePicker

jQuery 與 jQuery UI,其實都已經內建於 ASP.NET MVC 3 之中,你可以查看 Scripts 目錄之下,以我原生的 ASP.NET MVC 3 專案下,已經有 jquery-1.5.1.min.js 與 jquery-ui-1.8.11.min.js。

預設在 Site.Master 中有引用 jquery-1.5.1.min.js,但是沒有引用 jquery-ui-1.8.11.min.js,讓我們在Create.aspx 裡引用 jquery-ui-1.8.11.min.js 及寫一點點程式碼,以使用 jQuery UI 的 DatePicker 功能。

<!-- jQuery UI -->
<script src="<%: Url.Content("~/Scripts/jquery-ui-1.8.11.min.js") %>" type="text/javascript"></script>
<script type="text/javascript">
    $(function () {
        $('#PostedOn').datepicker();
    });
</script>

建置,把網頁執行起來,然後輸入「http://localhost:6944/BlogPostjQueryUI/Create」(記得Port要換成你的)。

jQuery UI - DatePicker
圖一:jQuery UI - DatePicker 
效果不是太好,讓我們加強一下。上面的 jQuery UI 醜醜的原因是因為我們還沒把 jQuery UI 的 CSS 檔案引用進來。讓我們把 jQuery UI 引用進來,相關 CSS 都在「~/Content/themes/base/」之下,這些檔案也是內建於 ASP.NET MVC 3 樣版內。

<!-- jQuery UI -->
<script src="<%: Url.Content("~/Scripts/jquery-ui-1.8.11.min.js") %>" type="text/javascript"></script>
<link href="<%: Url.Content("~/Content/themes/base/jquery.ui.all.css") %>" rel="stylesheet" type="text/css" />
<link href="<%: Url.Content("~/Content/themes/base/jquery.ui.datepicker.css") %>" rel="stylesheet" type="text/css" />
<script type="text/javascript">
    $(function () {
        $('#PostedOn').datepicker();
    });
</script>

我們必須引用兩個 CSS 檔案:jquery.ui.all.cssjquery.ui.datepicker.css。引用後,重新執行網頁。

jQuery UI - DatePicker with CSS
圖二:jQuery UI - DatePicker with CSS
終於美美了。但小問題又出現了!「10/05/2011」這個好像不是我們習慣使用的日期格式,接下去修改這個問題。

<script type="text/javascript">
    $(function () {
        // $('#PostedOn').datepicker();
        
        // 指定台灣習慣日期格式,例如,2011/9/23
        $("#PostedOn").datepicker({ dateFormat: "yy/mm/dd" });
    });
</script>

設定為日期格式為「年/月/日」。重新執行網頁。

jQuery UI - DatePicker 台灣日期格式
圖三:jQuery UI - DatePicker 台灣日期格式


注意,指定日期格式裡的 yy 只有兩碼,如果你打成 "yyyy/mm/dd",那你會得到「20112011/10/05」這個非日期內容。

到這裡,日期選擇器已經 100% 完成了。

大小決定速度

讓我再更進階一些討論 DatePicker。

jQuery UI 就 jquery-ui-1.8.11.min.js 此版本大小為 213 KB,未壓縮 368 KB。jQuery UI 本身是個強大 UI Framework,如果只是拿來做 DatePicker 功能,只寫一行程式碼,確要花費 213 KB ~ 368 KB 的頻寬資源,實在不太好。

讓我們再次打開 NuGet,搜尋 datepicker,

NuGet - jQuery UI Widgets: Datepicker
圖四:NuGet - jQuery UI Widgets: Datepicker
安裝jQuery UI Widgets : DatePicker之後,你的 Scripts 目錄下會多四支 Scripts:
  • jquery.ui.core.js
  • jquery.ui.core.min.js ( 5 KB )
  • jquery.ui.datepicker.js
  • jquery.ui.datepicker.min.js ( 35 KB )
此 jQuery UI Widgets : Datepicker 用意很簡單,就是只取出 jQuery UI 裡 DatePicker 所需的部分,獨立出來,讓只需要 DatePicker 功能的使用者,不必為了 DatePicker 功能去載入一個鐵金鋼。

213 KB VS 40 KB,結果很明顯了,jQuery UI Widgets : Datepicker "Win".

修改我們載入 Scripts:

<!-- jQuery UI -->
<!--
<script src="<%: Url.Content("~/Scripts/jquery-ui-1.8.11.min.js") %>" type="text/javascript"></script>
-->
<!-- 使用jQuery UI Widgets : Datepicker -->
<script src="<%: Url.Content("~/Scripts/jquery.ui.core.min.js") %>" type="text/javascript"></script>
<script src="<%: Url.Content("~/Scripts/jquery.ui.datepicker.min.js") %>" type="text/javascript"></script>
<link href="<%: Url.Content("~/Content/themes/base/jquery.ui.all.css") %>" rel="stylesheet" type="text/css" />
<link href="<%: Url.Content("~/Content/themes/base/jquery.ui.datepicker.css") %>" rel="stylesheet" type="text/css" />
<script type="text/javascript">
    $(function () {
        // $('#PostedOn').datepicker();
        
        // 指定台灣習慣日期格式,例如,2011/9/23
        $("#PostedOn").datepicker({ dateFormat: "yy/mm/dd" });
    });
</script>

重新執行網頁,一切運作正常。Very Good。

版本呀!版本!

還有呀,對,還沒寫完,你以為簡單的東西,越不簡單。讓我們先把 jQuery UI Widgets : Datepicker 移除。回復到使用 jquery-ui-1.8.11.min.js 情況。

我現在要模擬一個很常見的情況。像 jQuery 更新的速度很快,我們在開發一個專案期間,可能 jQuery 已經更新了三次。除非是特別版本,那種更新後會讓你的 jQuery 不會運作的版本,通常,三天到一週內,此特別版就被判死刑。我們會等個幾天或一到二週,然後把專案裡的 jQuery (或其他 Scripts) 做更新。

讓我們再打開 NuGet,更新目前所有內建 Scripts 至最新版本 ( 目前最新為 jQuery 1.6.4 )。

更新 jQuery 至 1.6.4 版本
圖五:更新 jQuery 至 1.6.4 版本
回到上個標題,我現在一個網頁,只單純使用 DatePicker 功能,所以我要去安裝 jQuery UI Widgets : Datepicker。

Installing : Operation failed.
圖六:Installing : Operation failed.
訊息內容:

Attempting to resolve dependency 'jQuery (≥ 1.4.4 && < 1.6)'.
Successfully installed 'jQuery 1.4.4'.
Successfully installed 'jQuery.UI.Core 1.8.9'.
Successfully installed 'jQuery.UI.Widgets.Datepicker 1.8.9'.
Install failed. Rolling back...
Already referencing a newer version of 'jQuery'.

好笑吧,我們反而給最新版本害到,還跟我說「是否已經是最新版的 jQuery」?。那怎麼辦?

自訂 jQuery UI Library

我們也不要太依賴工具,工具好用是不錯,但過度依賴就不是件好事。這種事,已經碰到很多次了。

讓我們上 jQuery UI 官網 → Download:

jQuery UI 自訂下載
圖七:jQuery UI 自訂下載 (點程看大圖)
你會發現,和平常的下載不太一樣,jQuery UI 可以讓我們自訂想要功能,然後產生對應功能最小化的 jQuery UI Library。這對我們來說,有很大的彈性。我們只需要勾選兩個:

  1. UI Core:勾選 Core
  2. Widgets:勾選 Datepicker

然後按「Download」下載我們自訂選擇好的 jQuery UI Library,目前我下載到的是 jquery-ui-1.8.16.custom.zip,解壓縮後,點擊 index.html , 裡面有一個簡易範例,我們查看一下它的 Source Code,發現它是載入一個「css/ui-lightness/jquery-ui-1.8.16.custom.css」與「js/jquery-ui-1.8.16.custom.min.js」就可以運作。

複製步驟:
  1. 把 css/ui-lightness/jquery-ui-1.8.16.custom.css 複製到專案 Content 目錄之下。
  2. 把 css/ui-lightness/images 的圖檔複製到專案 Content\images 目錄之下。
  3. 把 js/jquery-ui-1.8.16.custom.min.js 複製到 Scripts 目錄之下。
在 ASP.NET MVC 的目錄各有功能,所以把相對應的檔案放到正確的目錄之下。

更新 Site.Master 使用 jQuery 1.6.4,然後在我們 Create.aspx 引用我們新下載的 jquery-ui-1.8.16.custom.css 與 jquery-ui-1.8.16.custom.min.js。

<!-- 使用自訂 jQuery UI -->
<link href="<%: Url.Content("~/Content/jquery-ui-1.8.16.custom.css") %>" rel="stylesheet" type="text/css" />
<script src="<%: Url.Content("~/Scripts/jquery-ui-1.8.16.custom.min.js") %>" type="text/javascript"></script>
<script type="text/javascript">
    $(function () {
        // $('#PostedOn').datepicker();
        
        // 指定台灣習慣日期格式,例如,2011/9/23
        $("#PostedOn").datepicker({ dateFormat: "yy/mm/dd" });
    });
</script>

建置,重新執行網頁,我們能看到 jQuery 1.6.4 與 jquery-ui-1.8.16.custom.min.js 合作的很好。

語系呀,語系

「媽媽咪呀!你~你~你,寫夠了沒?」訪客說。
「最後,保證最後了。」KKBruce 說。
關於 jQuery UI : Datepicker 最後有個寶藏。我們最後自訂下載回來的  jquery-ui-1.8.16.custom.zip 解壓縮後,裡面有三個目錄,前面用了兩個,第三個就是寶藏。它的名字叫「Development-bundle ( 開發包 )」,裡面有更進階關於 jQuery UI : Datepicker 的相關資源。
  • demo : 相關範例程式。
  • docs:相關文件。
  • external:延伸的 JavaScript。
  • themes:樣版。
  • ui:介面相關 JavaScript。
我們只簡單介紹我認為最重要的一個「語系」。前面你有沒有發現,我們的 Datepicker 介面是英文的,而且你無從改起,無從設定,如果你不是走到自訂 jQuery UI 的地步,還真是沒辦法!

在「Development-bundle\ui\i18n\」之下,你能找到各語系資源檔案,只需要把你想要使用語系 *.js 引用到 Datepicker 頁面即可,Datepicker 頁面會自動切換為你所引用的語系介面。先複製 jquery.ui.datepicker-zh-TW.js 到專案 Scripts ,然後引用「jquery.ui.datepicker-zh-TW.js」這支語系資源檔。

<!-- 使用自訂 jQuery UI -->
<link href="<%: Url.Content("~/Content/jquery-ui-1.8.16.custom.css") %>" rel="stylesheet" type="text/css" />
<script src="<%: Url.Content("~/Scripts/jquery-ui-1.8.16.custom.min.js") %>" type="text/javascript"></script>
<!-- 使用 Taiwan 語系 -->
<script src="<%: Url.Content("~/Scripts/jquery.ui.datepicker-zh-TW.js") %>" type="text/javascript"></script>
<script type="text/javascript">
    $(function () {
        // $('#PostedOn').datepicker();
        
        // 指定台灣習慣日期格式,例如,2011/9/23
        $("#PostedOn").datepicker({ dateFormat: "yy/mm/dd" });
    });
</script>

建置,重新執行網頁。

jQuery UI : Datepicker 正體中文語系
圖八:jQuery UI : Datepicker 正體中文語系
那多國語系?可否自己切換?

可以,不過我不寫了,答案就在 Development-bundle 之中。

jQuery UI : Datepicker 使用心得

jQuery UI 不愧是 jQuery 的分支,和 jQuery 有一樣的特色「寫的更少,做的更多。」,簡單強大靈活彈性。當然,我們只是拿它來玩 Datepicker 功能,真的是大巫小用。

我覺得它有點像「斯斯」,什麼都可以醫,只有單一症狀時,拿它來吃好像有點浪費。但當你所有症狀都出現時,拿它來吃,你就會覺得它是仙丹!(這是什麼爛比喻!爛!爛!爛!)

參考資料

4 則留言:

  1. 我個人超討厭 jQuery UI 的覺得他實在太肥大了

    回覆刪除
  2. ^_^
    Demo 大大
    後面還有兩篇,再請指教。

    回覆刪除
  3. 請問 KKBruce 大大,我想在同一頁面放兩個日期選擇器,這該如何做呢?

    回覆刪除
    回覆
    1. 請參考jQuery語法,取得對應欄位在設定即可。

      刪除

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。