現在のプロジェクト:フォーム:すべてが検証される*ドロップダウンのための*を除き、.IsEmptyを使用していても()
- ASP.NET 4.5.2
- MVC 5
- Entity Frameworkの6
- FluentValidation
だから私は、全体の個々の要素とペアにされることを意図されている構造的に同一のテーブルある「ノート」の束を持っています少なくとも2ページと3ページ目にまとめられています。ノートを必要とするすべての要素は、単一の「サイクル」の一部です。したがって、要素は、ノートテーブルがハングしている同じテーブルのすべてのフラグメントです。たとえば、「プレゼンテーション」は、完了(イエス/ノー)ブール値とサイクルテーブルの日付で構成されます。プレゼンテーションノートは、サイクルテーブル(サイクルテーブルのプライマリキーである外部キーを持ちます)からハングする2つのサイクルカラムのための別個のテーブルです。これらのノートはプレゼンテーションのためのものなので、ノートテーブル全体はPresentationNotesと呼ばれます。サイクル内には独自のNotesテーブルを持つ多くの要素があり、プロジェクト全体のすべてのNotesテーブルは構造的に同一です。
この同じ構造から、モデルとビューを抽象化することができました。私は、単一のノートテーブルごとに異なるCRUDモデルとCRUDビューを複製する必要はありませんでした。私がコントローラーに持っていたのは、各notesテーブルのモデルを取り、特定のエントリーを汎用Notesモデルのgenericエントリーに関連付けることでした。
namespace CCS.Models {
public class CycleNotesPresentation {
[Key]
public Guid NotesId { get; set; }
[DisplayName("Cycle")]
public Guid CycleId { get; set; }
[DisplayName("Comm. Type")]
public Guid NotesStatusId { get; set; }
[DisplayName("Date")]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")]
public DateTime NotesDate { get; set; }
[DisplayName("Notes")]
[DataType(DataType.MultilineText)]
public string Notes { get; set; }
#region Essentials
//Essential DB components for each and every table. Place at end.
[HiddenInput, DefaultValue(true)]
public bool Active { get; set; }
[HiddenInput, Timestamp, ConcurrencyCheck]
public byte[] RowVersion { get; set; }
[HiddenInput]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")]
public DateTime Recorded { get; set; }
[HiddenInput]
public DateTime Modified { get; set; }
[HiddenInput]
public string TouchedBy { get; set; }
#endregion
[ForeignKey("CycleId")]
public virtual Cycle Cycle { get; set; }
[ForeignKey("NotesStatusId")]
public virtual NotesStatus NotesStatus { get; set; }
}
}
あなたが見ることができるように、必ずしも抽象化モデルとビュー内にある必要はありませんここにたくさんある:
は例えば、ここでは前述のプレゼンテーションモデルです。
少なくとも作成のための抽象化されたノートモデルは、、などである。もちろん
[Validator(typeof(CreateNotesValidator))]
public class CreateNotes {
public string NotesCategory { get; set; }
[DisplayName("Comm. Type")]
public string NotesStatusId { get; set; }
[DisplayName("Date")]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")]
public DateTime NotesDate { get; set; }
[DisplayName("Notes")]
public string Notes { get; set; }
}
、私は他の三つのモデルがあります:表示、編集をして削除しますが、今のところこの1つだけに集中しましょう。 Createを修正できるのであれば、クライアント側の検証が必要なドロップダウンメニューを持つ唯一のEditです。
上記の違いに注意してください。NotesStatusId
フィールドは実際にはGuidの代わりに文字列です。さて、Guidを使っていれば、クライアント側の検証オプションが非常に限られていることが分かります。さらに、クライアント側の検証はまだGuidで動作していなかったので、代わりに文字列を使用してModel(したがって検証)を単純化することにしました。
元のプレゼンテーションモデルをプルすると、Guidから文字列に変換され、Notesモデルを処理してプレゼンテーションモデルに戻すと、その文字列をGuidに変換し直します。これにより、クライアント側の検証オプションを増やすことができます。
全体のプロセスのための私のコントローラのようなである:ここでは
// GET: Onboarding/CreateCycleNotesPresentation
[HttpGet]
public ActionResult CreateCycleNotesPresentation() {
var model = new CreateNotes() {
NotesCategory = "Presentation",
NotesDate = DateTime.Now
};
ViewBag.NotesStatusId = new SelectList(db.NotesStatus.Where(x => x.Active == true), "NotesStatusId", "NotesStatusName");
return PartialView("_CreateNotesPartial", model);
}
// POST: Onboarding/CreateCycleNotesPresentation
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> CreateCycleNotesPresentation(CreateNotes model) {
if(ModelState.IsValid) {
var id = new Guid(User.GetClaimValue("CWD-Cycle"));
CycleNotesPresentation cycleNotes = new CycleNotesPresentation();
cycleNotes.NotesId = new Guid();
cycleNotes.CycleId = id;
cycleNotes.NotesStatusId = new Guid(model.NotesStatusId);
cycleNotes.NotesDate = model.NotesDate;
cycleNotes.Notes = model.Notes;
cycleNotes.Active = true;
cycleNotes.Recorded = DateTime.UtcNow;
cycleNotes.Modified = DateTime.UtcNow;
cycleNotes.TouchedBy = User.Identity.GetFullNameLF();
db.CycleNotesPresentation.Add(cycleNotes);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
model.NotesCategory = "Presentation";
ViewBag.NotesStatusId = new SelectList(db.NotesStatus.Where(x => x.Active == true), "NotesStatusId", "NotesStatusName", model.NotesStatusId);
return PartialView("_CreateNotesPartial", model);
}
我々はいくつかのジューシーなビットを見ることを得る - 私はNotesCategory
エントリを追加したビューは、要素のタイトルを移入することができるようにメモが追加されています。これは最後には処理されません。
また、ページ全体を更新してPOSTを終了します。 JSONの送信が正しく行われなかったため(実際のPOSTメソッドがデータを受け取っていないため、送信がハングアップする可能性があるため)、これが最も簡単な解決策であることがわかりました。また、ページ全体が更新され、全体的なページが改善されます。それでは、それだけを残しましょう、k?
は、今最も重要なことのために:抽象ノートモデルとビューのためのバリデータ:これは私たちが取り組んでいるものではないよう
namespace CCS.Validators {
class NotesValidator {
}
public class CreateNotesValidator : AbstractValidator<CreateNotes> {
public CreateNotesValidator() {
RuleFor(x => x.NotesDate)
.NotEmpty().WithMessage("Please select a date that this communication occurred on.");
RuleFor(x => x.NotesStatusId)
.NotEmpty().NotNull().WithMessage("Please indicate what type of communication occurred.");
RuleFor(x => x.Notes)
.NotEmpty().WithMessage("Please submit notes of some kind.")
.Length(2, 4000).WithMessage("Please provide notes of some substantial length.");
}
}
public class EditNotesValidator : AbstractValidator<EditNotes> {
public EditNotesValidator() {
RuleFor(x => x.NotesDate)
.NotEmpty().WithMessage("Please select a date that this communication occurred on.");
RuleFor(x => x.NotesStatusId)
.NotNull().NotEmpty().NotEqual("00000000-0000-0000-0000-000000000000").Matches("^[{(]?[0-9A-F]{8}[-]?([0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$").WithMessage("Please indicate what type of communication occurred.");
RuleFor(x => x.Notes)
.NotEmpty().WithMessage("Please submit notes of some kind.")
.Length(2, 4000).WithMessage("Please provide notes of some substantial length.");
}
}
}
私たちは、主に、今のEditNotesValidator
を無視することができます。
ビューには、抽象化されたノートのための単純な部分で、フォーム自体を約あなたが得ることができるようにバニラの通りです:ええ、そう
@model CCS.Models.CreateNotes
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title">Create Note for “@Model.NotesCategory”</h3>
</div>
@using(Html.BeginForm()) {
@Html.AntiForgeryToken()
<div class="modal-body">
<fieldset>
@Html.LabelFor(m => Model.NotesDate, new { @class = "control-label" })<div class="input-group date">@Html.TextBoxFor(m => m.NotesDate, "{0:yyyy-MM-dd}", new { @class = "form-control date" })<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span></div>
@Html.ValidationMessageFor(m => m.NotesDate)
@Html.LabelFor(m => Model.NotesStatusId, new { @class = "control-label" })@Html.DropDownList("NotesStatusId", null, "« ‹ Select › »", htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.NotesStatusId)
@Html.LabelFor(m => Model.Notes, new { @class = "control-label" })@Html.TextAreaFor(m => m.Notes, new { @class = "form-control required" })
@Html.ValidationMessageFor(m => m.Notes)
</fieldset>
</div>
<div class="modal-footer">
<span id="progress" class="text-center" style="display: none;">
<img src="/images/wait.gif" alt="wait" />
Wait..
</span>
<button type="submit" value="Save" title="Save" class="btn btn-primary glyphicon glyphicon-floppy-disk"></button>
<button class="btn btn-warning" data-dismiss="modal">Close</button>
</div>
}
<script>
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
$(function() {
$.fn.datepicker.defaults.format = "yyyy-mm-dd";
$(".date").datepicker();
});
</script>
。 Dateバリデータは、期待どおりに動作します。 Notesテキストエリアは美しく検証されます。しかし、ドロップダウンメニューは完全に昼食になります。私が試してみても、それは.NotEmpty()
または.NotNull()
であるか、またはFluentValidationによってクライアント側で機能していると明確にフラグが付けられているものは、ドロップダウンメニューでは何も動作しません。
<select id="NotesStatusId" class="form-control" name="NotesStatusId">
<option value="">« ‹ Select › »</option>
<option value="98e9f033-20df-e511-8265-14feb5fbeae8">Phone Call</option>
<option value="4899dd4d-20df-e511-8265-14feb5fbeae8">eMail</option>
<option value="8c073863-20df-e511-8265-14feb5fbeae8">Voice Mail</option>
<option value="8a13ec76-20df-e511-8265-14feb5fbeae8">Meeting</option>
</select>
とデフォルト« ‹ Select › »
最初のオプションのためにその空の値は.NotEmpty()
と.NotNull()
が完璧に動作する必要があることを意味する必要があります生のHTMLのチェックは、私がSelectListのが適切に構築取得していますことを示しています。しかし、彼らはそうではありません。日付を消去すると(上記のコントローラを参照してください)、日付フィールドとテキストエリアにのみフラグが立てられ、ドロップダウンにはフラグが立てられませんまったく。
提案?
編集1: Ehehは、おっと...今、間違ったコントローラ...固定を追加しました。
編集2: ... Bueller? ...ブエラー?
編集3:私はそれが困難な他の誰が今までFluentValidationを経由して、ドロップダウンメニューには、クライアント側の検証を行って問題がなかったしていることを信じることを発見しています。