ASP.NET MVC5 で Controller で Model に日付を設定して View に渡し、Html ヘルパーの EditorFor を使ってテキストボックスにその日付を表示したとします。そのテキストボックスに bootstrap datepicker を適用してカレンダーを表示した際、 Model に設定した日付がカレンダー上で選択されるようにする方法を備忘録として残しておきます。
自動的に Model に設定した日付が bootstrap datepicker のカレンダー上で選択されて表示されると思っていたのですが、何もしないと Model に設定した日付ではなくてブラウザに表示された当日の日付になってしまいます。
その原因は、例えば new DateTime(2021, 3, 23) としてそれを Model に設定すると、テキストボックスに 2021/03/23 0:00:00 と表示される(当該 html input 要素で value="2021/06/24 0:00:00" となる)、即ち 0:00:00 部分が bootstrap datepicker にとって余計で日付を判定できなかったからのようです。
なので、当該 html input 要素で value="2021/03/23" となるようにすれば bootstrap datepicker のカレンダー上もその日付を選択して表示するようになります。
そのためには、Model の当該プロパティに DisplayFormatAttribute 属性を付与してやります。具体的には以下のようにします。その結果が上の画像です。
(1) Model
using System;
using System.ComponentModel.DataAnnotations;
namespace Mvc5App.Models
{
public class BootstrapDatepickerModel
{
[Display(Name = "日付")]
[DisplayFormat(ApplyFormatInEditMode = true,
DataFormatString = "{0:yyyy/MM/dd}")]
public DateTime? OrderDate { get; set; }
}
}
Visual Studio 2019 のテンプレートを使って ASP.NET Web アプリを作ると、Bootstrap.js と Bootstrap.css が自動的にプロジェクトに含まれますが、bootstrap datepicker はその中には含まれていませんので注意してください。別途 github のサイト uxsolutions/bootstrap-datepicker 等からダウンロードする必要があります。この記事では、この記事を書いている時点での最新版 1.9.0 を使用しました。
また、bootstrap datepicker は Boorstrap 本体のバージョン 4 以上には対応してないそうです (Bootstrap 4 および 5 でも使う方法があるそうですが未検証・未確認です)。この記事で使った Bootstrap のバージョンは、MVC5 アプリのテンプレートに含まれている v3.4.1 です。
ご参考に View と Controller / Action Metod のコードも以下に載せておきます。
(2) View
@section Scripts { ... } 内の link 要素、script 要素による外部 bootstrap datepicker の js ファイル、css ファイルへの参照に注目してください。
@model Mvc5App.Models.BootstrapDatepickerModel
@{
ViewBag.Title = "Datepicker";
}
<h2>Datepicker</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>BootstrapDatepickerModel</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.OrderDate,
htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.OrderDate,
new { htmlAttributes = new { @class = "form-control datepicker" } })
@Html.ValidationMessageFor(model => model.OrderDate, "",
new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
<link href="~/Content/bootstrap-datepicker.css" rel="stylesheet" />
<script src="~/Scripts/bootstrap-datepicker.js"></script>
<script src="~/Scripts/locales/bootstrap-datepicker.ja.min.js"></script>
@Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
//<![CDATA[
$(function () {
$('.datepicker').datepicker({
format: 'yyyy/mm/dd',
language: 'ja'
});
})
//]]>
</script>
}
(3) Controller / Action Method
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Mvc5App.DAL;
using System.Data.Entity;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
using Mvc5App.Models;
using System;
namespace Mvc5App.Controllers
{
public class HomeController : Controller
{
public ActionResult Datepicker()
{
var model = new BootstrapDatepickerModel();
model.OrderDate = new DateTime(2021, 3, 23);
// model.OrderDate が null なら今日の日付を表示する
if (model.OrderDate == null)
{
model.OrderDate = DateTime.Now;
}
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Datepicker(BootstrapDatepickerModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View(model);
}
}
}