How to make my html helpers in razor templates more reusable?
I have a form with multiple addresses. A business address, a billing address, and a shipping address. Naturally I want to use the same code.
My razor template looks something like this:
<div class="std-form-line">
<span class="std-form-no开发者_高级运维-label"></span>
@Html.TextBoxFor(x => x.BillingAddress.Line2, new { Class = "optional" })
@Html.ValidationMessageFor(x => x.BillingAddress.Line2)
</div>
<div class="std-form-line">
<span class="std-form-no-label"></span>
@Html.TextBoxFor(x => x.BillingAddress.Line3, new { Class = "optional" })
@Html.ValidationMessageFor(x => x.BillingAddress.Line3)
</div>
....
And when rendered looks something like this:
<input type="text" value="" name="BillingAddress.Line1" id="BillingAddress_Line1" data-val-required="The Street Address field is required." data-val="true" class="text-box single-line">
Now say I will have the same code, for Business and shipping but it will look like this:
<div class="std-form-line">
<span class="std-form-no-label"></span>
@Html.TextBoxFor(x => x.BusinessAddress.Line2, new { Class = "optional" })
</div>
<div class="std-form-line">
<span class="std-form-no-label"></span>
@Html.TextBoxFor(x => x.BusinessAddress.Line3, new { Class = "optional" })
</div>
How can I get rid of this code duplication?
The way I do it, is to create strongly typed Display/Editor templates for "Address".
Then call @Html.EditorFor(x=>x.BusinessAddress)
or @Html.DisplayFor(x=>x.BusinessAddress)
You can also create different templates for different uses, and then optionally supply the name of the template in the Editor/DisplayFor methods.
BTW, the templates I mention may reside in the ~Views/Shared/EditorTemplates or ~Views/Shared/DisplayTemplates folders, respectively. Or they may reside with in a specific Controllers views folder, under EditorTemplates or DisplayTemplates.
Edit: Here is a link that demonstrates this. Editor Tempates
Edit 2: Here is an example to try and explain further, per your comment.
Address Model
public partial class Address
{
public int AddressId { get; set; }
public string Street1 { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
Editor Template: This file is named "Address.cshtml" and located in my "~Views/Shared/EditorTemplates" folder.
@model Address
@Html.HiddenFor(model => model.AddressId)
<div class="editor-label">
@Html.LabelFor(model => model.Street1)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Street1)
@Html.ValidationMessageFor(model => model.Street1)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Street2)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Street2)
@Html.ValidationMessageFor(model => model.Street2)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.City)
@Html.ValidationMessageFor(model => model.City)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.State)
</div>
<div class="editor-field">
@* Populated from Helper *@
@Html.DropDownListFor(m => m.State, new SelectList(statesDictionary, "Key", "Value"), string.Empty)
@Html.ValidationMessageFor(model => model.State)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Zip)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Zip)
@Html.ValidationMessageFor(model => model.Zip)
</div>
Create View: This is my view that will implement the editor template for my model. Note the line @Html.EditorForModel();
@model Address
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<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>Address</legend>
@Html.EditorForModel()
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
Now if my model for my view was something else, that linked to an "Address", I would have used @Html.EditorFor(model => model.BusinessAddress)
As for the names, that's completely under your control. By default, they get mapped to you property names, but you can change any by supplying an object containing your html attribues in the EditorFor
overloads.
I don't see any duplication to get rid of in the DRY sense. If you have 3 similar fields on a form, you will need three similar elements in the markup.
Why not introduce an AddressType field? All 3 address types you mention share the same fields just their type is different; what will set each appart is the value of AddressType. Make sense?
精彩评论