4

To be honest, I have no idea what to call this or how to start to search it.

I have a display page with a standard layout.

<div>
    <label for="field">Field Name:</label>
    @Model.Field
</div>

While trying to make this more change friendly, I want to make a template instead of typing out each field with the above code.

I created a partial view with the following:

@model System.Object
<div>
    @Html.LabelFor(m => m)
    @Html.DisplayFor(m => m)
</div>

On my view, I added the following:

@Html.Partial("_BillField", Model.Field)

The model then has a description with like:

public ModelName {
    [Display(Name="Field Description")]
    public decimal Field { get; set; }
}

This works when on the main view, but the label is missing when using the template. What am I missing?

Update: Per @K. Bob I make the change to the partial view:

<div>
    @Html.LabelFor(m => m)
    @Html.DisplayFor(m => m)
</div>

Update 2: For clarity of what I want.

In the end, I want to be able to do:

@Html.Partial("_BillField", Model.Field1)
@Html.Partial("_BillField", Model.Field2)
@Html.Partial("_BillField", Model.Field3)

And have the equivalent of:

<div>
    <label for="field1">Field 1 Name:</label>
    @Model.Field1
</div>
<div>
    <label for="field2">Field 2 Name:</label>
    @Model.Field2
</div>
<div>
    <label for="field3">Field 3 Name:</label>
    @Model.Field3
</div>

Sorry for not making that clearer.

Mike Wills
  • 20,959
  • 28
  • 93
  • 149
  • Note that the argument to `LabelFor` et al is not a `Func`, but an `Expression`. This is because it can use that to access the model member (that is, its value, type, name, and attributes, e.g. `DisplayName`) via reflection. When you pass the model member directly through to the partial, you're changing that expression, so it can no longer access the member in situ, and can only access the type and value of the member, because it lacks the context of the model. – jpaugh Jun 08 '17 at 18:27
  • What you probably want is a custom model binder, or a model binder template, although I don't have experience with those. – jpaugh Jun 08 '17 at 18:30

5 Answers5

2

The partial doesn't need told what the @model is, it'll use the parent @model, if you take out the @model in the partial does that help?

If I have this as the view....

@model MyApp.Models.ModelName
@{
    ViewBag.Title = "Test";
}

<h2>Test</h2>
<div>
           <div class="editor-label">
                @Html.LabelFor(m => m.Field)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(m => m.Field)
                @Html.ValidationMessageFor(m => m.Field)
            </div>
</div>
@Html.Partial("_partial", Model) @*note I pass the whole model*@

And this as the partial....

@model MyApp.Models.ModelName
<div>
              <div class="editor-label">
                @Html.LabelFor(m => m.Field)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(m => m.Field)
                @Html.ValidationMessageFor(m => m.Field)
            </div>
</div>

Then it does what I think you want to do (obv. it does it twice but you could remove the code from the main view). I'm not sure it gives you a huge benefit though. Maybe I've misunderstood something.

K. Bob
  • 2,668
  • 1
  • 18
  • 16
  • No, it did not. Fixing question to reflect the change – Mike Wills Nov 21 '11 at 17:38
  • @Mike - When you call this `@Html.Partial("_BillField", Model.Field)` it's only passing the value of the Field property, not the whole field property as a property that has dataannotations attached to it (if you see what I mean) – K. Bob Nov 21 '11 at 18:18
  • @MikeWills - I've updated my answer with a working example, so ignore the bit about not having the model declared for this example. You don't need the model if you're passing a value (like Model.Field). – K. Bob Nov 21 '11 at 18:40
  • But I wanted a generic thing that could be reused. So I could just do `@Html.Partial("_BillField", Model.Field)` `@Html.Partial("_BillField", Model.Field2)` `@Html.Partial("_BillField", Model.Field3)` etc. I'll add to question as well. – Mike Wills Nov 21 '11 at 19:26
  • @MikeWills - Is what you're looking for an HTMLHelper that produces HTML that is an aggregate of the other HTMLHelpers, is that right? You give it the Model and without having to write three 'chunks' of Helper code you only write one? I'd ask a new question to that effect if that is what you're looking for. – K. Bob Nov 21 '11 at 19:32
1

You don't need to ToString() your property.

@Html.LabelFor(m => m)

UPDATED

Based on what you want to do, re-use views, take a look at this longer than normal post about reuse of validation and partial views I wrote up to the answer for ASP.NET MVC 3 - Model Validation. It is extremely detailed.

Community
  • 1
  • 1
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • Oops. Bad copy-paste. The `ToString()` blew up the page and I forgot to remove it before posting. That is fixed in original post. – Mike Wills Nov 21 '11 at 17:36
1

I think that potentially you should use Display/Editor templates for types, your model includes 3 fields of that type.

@Html.Partial("_BillField", Model.Field1)
@Html.Partial("_BillField", Model.Field2)
@Html.Partial("_BillField", Model.Field3)

Defining a Template for the type rather than a Partial view is possibly more effective. See ASP.NET MVC 3 - Partial vs Display Template vs Editor Template for a detailed comparison.

In this case your View would look more like:

@Html.DisplayFor(model => model.Field1)
@Html.DisplayFor(model => model.Field2)
@Html.DisplayFor(model => model.Field3)

Your model would be:

public class model
{
   [DisplayName("Field1")]
   public ComplexType Field1 {get;set;}
   [DisplayName("Field2")]
   public ComplexType Field2 {get;set;}
   [DisplayName("Field3")]
   public ComplexType Field3 {get;set;}
}

Or whatever the data annotation is for the display name.

Community
  • 1
  • 1
JTew
  • 3,149
  • 3
  • 31
  • 39
0

Added a new answer as the other one didn't answer the question once clarified. This post LabelFor extension should be able to be adjusted to suit your needs I think, but rather than override better to create your own extension.

You'll need to call it slightly differently from how you've proposed because you need to use the m=>m.Field syntax. But I'm sure this should do what you need without having to use a partial view.

If you use Model.Field syntax you will only ever send in the actual value of the Field property, like 1.23 for your decimal, you need to use the m=>m.Field to get more than just the evaluation of the property so that you can change the text in the label.

Community
  • 1
  • 1
K. Bob
  • 2,668
  • 1
  • 18
  • 16