Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp.Net Razor View Passing Expression To Partial

I find myself writing this a whole lot in my views:

<div class="form-group">
    @Html.LabelFor(x => x.City)
    @Html.EditorFor(x => x.City)
    @Html.ValidationMessageFor(x => x.City)
</div>

I'd really like to put this in a Partial _Field.cshtml, something like this:

@model //what model type???

<div class="form-group">
    @Html.LabelFor(Model)
    @Html.EditorFor(Model)
    @Html.ValidationMessageFor(Model)
</div>

That could then be called by:

@Html.Partial("_Field", x => x.City)

What would the @model type in my partial be if I wanted to accomplish something like this?

UPDATE This works, but I'd rather use a partial for ease of changing the template:

public static MvcHtmlString Field<TModel, TItem>(this HtmlHelper<TModel> html, Expression<Func<TModel, TItem>> expr)
{
  var h = "<div class='form-group'>";
  h += $"{html.LabelFor(expr)}{html.EditorFor(expr)}{html.ValidationMessageFor(expr)}";
  h += "</div>";

  return MvcHtmlString.Create(h);
}
like image 493
mxmissile Avatar asked Jan 25 '26 16:01

mxmissile


1 Answers

That's not possible. However, what you want is very similar to editor templates. Essentially, you just create a view in Views/Shared/EditorTemplates named after one of the following conventions:

  • A system or custom type (String.cshtml, Int32.cshtml, MyAwesomeClass.cshtml, etc.)
  • One of the members of the DataType enum (EmailAddress.cshtml, Html.cshtml, PhoneNumber.cshtml, etc.). You would then apply the appropriate DataType attributes to your properties:

    [DataType(DataType.EmailAdress)]
    public string Email { get; set; }
    
  • Any thing you want, in conjunction with the UIHint attribute:

    [UIHint("Foo")]
    public string Foo { get; set; }
    

    Which would then correspond to a Foo.cshtml editor template

In your views, then, you simply use Html.EditorFor:

@Html.EditorFor(x => x.City)

Then, for example, you could have Views/Shared/EditorTemplates/String.cshtml as:

<div class="form-group">
    @Html.Label("", new { @class = "control-label" })
    @Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "form-control" })
    @Html.ValidationMessage("")
</div>

(The empty quotes are placeholders. Razor will automatically fill in the appropriate property name, thankfully.)

Calling EditorFor, then, will print all of this, rather than just the default text input. You can take this much further, as well. I have some articles on my blog that goes into greater detail, if you're interested.

UPDATE

It's worth mentioning a few features of EditorFor:

  1. You can pass a template directly to the call, meaning you can customize what template is used on the fly and per instance:

    @Html.EditorFor(x => x.City, "MyCustomEditorTemplate")
    
  2. You can pass additionalViewData. The members of this anonymous object are added to the ViewData dynamic dictionary. Potentially, you could use this to branch within your editor template to cover additional scenarios. For example:

    @Html.EditorFor(x => x.City, new { formGroup = false })
    

    Then in your editor template:

    @{ var formGroup = ViewData["formGroup"] as bool? ?? true; }
    @if (formGroup)
    {
        <!-- Bootstrap form group -->
    }
    else
    {
        <!-- Just the input -->
    }
    
like image 178
Chris Pratt Avatar answered Jan 28 '26 07:01

Chris Pratt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!