.NET MVC RazorでTODOList(動的なフォーム)を作成する方法があった
何気に痒い所に手が届かない.NET MVC RazorですがTODOListのような動的フォームを作成する方法がありました
本来ならScriptメインで記述すればいいのですが、Validationや共通のヘルパーなどを使用したかったのでRazorでやりたかったのです。
使ったライブラリ
www.nuget.org
んで実現のために作ったサンプルコードはこちら
Controller
// SampleController.cs public class SampleController { /// <summary> /// 初期レンダリング時にkickされる /// </summary> /// <returns></returns> [HttpGet] public ActionResult Index() { // サンプルの為、DBロジックをハードコーディングしてます。 var parent = new Parent() { Age = 4, Name = "ねこのきなこ", Skills = new List<Skill>() { new Skill() {Name = "お皿洗い", Experience = 2 }, new Skill() {Name = "あまえる", Experience = 4 }, } }; return View(parent); } /// <summary> /// submit時にkick /// </summary> /// <param name="model"></param> /// <returns></returns> [HttpPost] public ActionResult Create(Parent model) { // 登録処理 return View("Index"); } /// <summary> /// スキル追加 /// </summary> /// <returns></returns> [HttpGet] public ActionResult AddChild() { return PartialView("Skills", new Skill()); } }
Model側
// Parent.cs public class Parent { [Display(Name = "おなまえ")] public string Name { get; set; } [Display(Name = "おとし")] public int Age { get; set; } [Display(Name = "できることリスト")] public List<Skill> Skills { get; set; } }
// Skill.cs public class Skill { [Display(Name = "できること")] public string Name { get; set; } [Display(Name = "つづけたねんすう")] public int Experience { get; set; } }
View側
Index.cshmlt
@model HogeHogeNameSpace.Parent @section Scripts { <script src="~/js/sample.js"></script> } @using (Html.BeginForm("Create", "Sample")) { <div class="mdl-grid"> @Html.CustomTextEditorFor(m => m.Name, 50) </div> <div class="mdl-grid"> @Html.CustomNumericEditorFor(m => m.Age, 2) <span>さい</span> </div> <table id="children"> <tbody> @foreach (var skill in Model.Skills) { @Html.Partial("_Skills", skill) } </tbody> </table> @Html.CustomTextButton("addChild", "Skill追加", "mode_edit") @Html.CustomTextButton("Save", "Save", "mode_edit", null, "submit"); }
_Skills.cshtml
@model HogeHogeNameSpace.Skill @using HtmlHelpers.BeginCollectionItem; <!---使用するとHtmlのName属性の衝突を避けることが出来て、CollectionのItemに応じたIdが割り当てされる--> @using (Html.BeginCollectionItem("Skills")) { <tr> <td> @Html.CustomTextEditorFor(m => m.Name, 50, false) @Html.CustomNumericEditorFor(m => m.Experience, 2, false) <span>ねん</span> </td> <td> @Html.CustomButtonIcon("removeItem", "close", "close", new Dictionary<string, string>() { { "data-action", "removeItem" } }) </td> </tr> }
sample.js
$("#addChild").on("click", function () { $.ajax({ // urlの置換 url: '/Sample/AddChild' , success: function (partialView) { $('#children> tbody:last-child').append(partialView); } }); });
完成した画面はこちら。Frameworkをカスタムヘルパーで参照しています。これがしたかったのです。
画面初期時
スキル追加ボタン押下時
実装のコツとしては各リストをパーシャル化してBeginCollectionItemを使用する。
第一引数に対応するCollectionNameを入力
この場合、Parentから呼び出されているので、"Skills"ですね。
次にコントローラーにスキルを追加する為のルーティングを用意します。
AddChildで空のSkillを返してあげてAjaxでRequest、Responseを処理します。
結構簡単な事なのにRazorでやろうとしたら大変だったなぁ。
でもValidationとか割とモデル内で書けるから便利だったりするので、この方法で動的リストを作ろうと思いましたっ。
参考にしたリンク
stackoverflow.com