asp.netasp.net-coremvc-editor-templates

Create Custom Editor in ASP.NET Core


I am in need of some advice. I am wanting to implement my own custom editor for a specific object type, Address. I started by reading the documentation for Tag Helpers on the .NET Core website and then read about View Components on the Core site and neither really made since for my exact scenario.

I have a model Address:

public class Address
{
    public Guid Id { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string StateCode { get; set; }
    public string PostalCode { get; set; }
}

I want to create either a custom editor template, tag helper, or view component that will allow me to do something like this (In my "Edit" View):

@model TestApplication.Models.Customer

<h2>Edit Customer</h2>

<form asp-action="Edit">
    <div class="form-horizontal">
    <h4>Edit Customer</h4>
    <hr />
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <input type="hidden" asp-for="Id" />
    <div class="form-group">
        <label asp-for="Name" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="Name" class="form-control" />
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
    </div>
    <address-editor asp-for="HomeAddress" />
    <address-editor asp-for="WorkAddress" />
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
</form>

I would like the HTML to be rendered like so:

Edit Customer

<form asp-action="Edit">
    <div class="form-horizontal">
    <h4>Edit Customer</h4>
    <hr />
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <input type="hidden" asp-for="Id" />
    <div class="form-group">
        <label asp-for="Name" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="Name" name="Name" class="form-control" />
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
    </div>
    <h4>Home Address</h4>
    <input type="hidden" asp-for="HomeAddress_Id" />
    <div class="form-group">
        <label asp-for="HomeAddress_AddressLine1" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="HomeAddress_AddressLine1" name="HomeAddress_AddressLine1" class="form-control" />
        </div>
    </div>
    <div class="form-group">
        <label asp-for="HomeAddress_AddressLine2" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="HomeAddress_AddressLine2" name="HomeAddress_AddressLine2" class="form-control" />
        </div>
    </div>
    <div class="form-group">
        <label asp-for="HomeAddress_City" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="HomeAddress_City" name="HomeAddress_City" class="form-control" />
        </div>
    </div>
    <div class="form-group">
        <label asp-for="HomeAddress_StateCode" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="HomeAddress_StateCode" name="HomeAddress_StateCode" class="form-control" />
        </div>
    </div>
    <div class="form-group">
        <label asp-for="HomeAddress_PostalCode" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="HomeAddress_PostalCode" name="HomeAddress_PostalCode" class="form-control" />
        </div>
    </div>
    <h4>Work Address</h4>
    <input type="hidden" asp-for="WorkAddress_Id" />
    <div class="form-group">
        <label asp-for="WorkAddress_AddressLine1" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="WorkAddress_AddressLine1" name="WorkAddress_AddressLine1" class="form-control" />
        </div>
    </div>
    <div class="form-group">
        <label asp-for="WorkAddress_AddressLine2" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="WorkAddress_AddressLine2" name="WorkAddress_AddressLine2" class="form-control" />
        </div>
    </div>
    <div class="form-group">
        <label asp-for="WorkAddress_City" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="WorkAddress_City" name="WorkAddress_City" class="form-control" />
        </div>
    </div>
    <div class="form-group">
        <label asp-for="WorkAddress_StateCode" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="WorkAddress_StateCode" name="WorkAddress_StateCode" class="form-control" />
        </div>
    </div>
    <div class="form-group">
        <label asp-for="WorkAddress_PostalCode" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input id="WorkAddress_PostalCode" name="WorkAddress_PostalCode" class="form-control" />
        </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>
</form>

Am I on the right direction by looking into Editor Templates? If so, how do I prefix the control names with the Model.PropertyName (i.e. HomeAddress_)?


Solution

  • I believe my answer came about by researching view components a bit more. I could have gone the direction of a tag helper, view component, or editor template. I decided on view component and needed to know how to pass the entire model information into the view component, well, this question helped me get there. The issue I was having (or question) was that I needed to know about ModelExpression. That class contains everything that I need (name and model), so I was able to do like the following:

    <vc:address-editor asp-for="@Model.HomeAddress"></vc:address-editor>
    

    Then, in my AddressEditor ViewComponent, I simply used the two properties that I needed:

     public IViewComponentResult Invoke(ModelExpression aspFor)
     {
         ViewBag.AspFor = aspFor.Name;
    
         return View(aspFor.Model);
     }