32

I have a couple of properties in my view model that are display-only but I need to retrieve their values using jQuery to perform a calculation on the page. The standard Html.DisplayFor() method just writes their value to the page. I want to create a razor template that will allow me to render each element as:

<span id="ElementsId">Element's value</span>

I know I can specify a template in Html.DisplayFor() to use a particular template for rendering the property but within that template how do I identify the id attribute to write into the span tag?

@Html.DisplayFor(model => model.Element, "MyTemplate");
David Clarke
  • 12,888
  • 9
  • 86
  • 116

6 Answers6

60

OK, I found it and it's actually very simple. In my Views\Shared\DisplayTemplates folder I have Reading.cshtml containing the following:

@model System.Int32
<span id="@ViewData.ModelMetadata.PropertyName">@Model</span>

This renders the correct tag using the name of the property as the id attribute and the value of the property as the contents:

<span id="Reading">1234</span>

In the view file this can be called using the following:

@Html.DisplayFor(model => model.Reading, "Reading")

Or if the model property is decorated with UIHint("Reading") then the template name can be left out of the call to DisplayFor() and it will still render using the template:

@Html.DisplayFor(model => model.Reading)

This should work equally well with custom editor templates.

David Clarke
  • 12,888
  • 9
  • 86
  • 116
  • So how do you handle `System.Int32?` (Nullable int). You can't make another view named `Int32?.cshtml` – The Muffin Man Aug 29 '13 at 02:41
  • The view is called Reading.cshtml, not Int32.cshtml. So if you have an `Int32?` property, you would create a new file `WhateverPropertyIsCalled.cshtml`, with `@model System.Int32?`. Disclaimer: I don't recall having this requirement myself and I haven't tested that this works. – David Clarke Sep 05 '13 at 21:33
  • 4
    I actually tested this out and if you create a file named `Int32.cshtml` with a model of `System.Int32?` you will override the default template and it will be picked up by both versions of int32 (nullable and not nullable). – The Muffin Man Sep 08 '13 at 06:09
  • 1
    Depending on how you are outputting the value inside the template, it might be a good idea to check for null and provide a default formatting when this occurs. I just did this on a similar template for currency values. When the user first gets your form, the value will be null (nothing entered yet.) – Neil Monroe Jun 27 '14 at 18:22
  • I am using a configurable template, so I feel the foreach loop can only be used in my case, as the partial views are not available to the end users convenience. – MGR Sep 27 '15 at 10:30
11

I read many SO posts about defining template for @Html.DisplayFor for Boolean property but I couldn't clearly understand them. Your question is closed to this and after grasping it, I decided to add a new answer including all steps needed for implementing that. It might be helpful for other people.

1. Creating a template

At first, you need to add a Partial View in path below (the path is very important):

Views/Shared/DisplayTemplates/

For example, I created a Partial View that named _ElementTemplate and Fill it like this:

<span>
    @(@Model ? "Yes" : "No")
</span>

2. Adding UIHint to the Model

To make a connection between your property and template, you should add UIHint attribute like below in your model class:

[UIHint("_YesOrNoTemplate")]
public bool MyProperty { get; set; }

3. Using @Html.DisplayNameFor in View

In every view that you need this property, you can use code below:

<div>
    @Html.DisplayFor(modelItem => item.MyProperty)
</div>

Output

The code above is rendered to code below in my example (if (MyProperty == true)):

<div>
    <span>
        Yes
    </span>
</div>

Setting attributes

For setting id or other html attributes you can use ModelMetadata like this:

<span id="@ViewData.ModelMetadata.PropertyName">
    @(@Model ? "Yes" : "No")
</span>

Output with attribute

<div id="MyProperty">
    <span>
        Yes
    </span>
</div>
Ali Soltani
  • 9,589
  • 5
  • 30
  • 55
7

You could make this id part of the view model and use it in the display template:

<span id="@Model.Id">@Html.DisplayFor(x => x.Value)</span>
David Clarke
  • 12,888
  • 9
  • 86
  • 116
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
3

There's an article explaining the Templates (Display + Editor) in Razor, and also the UIHint attribute.

David Clarke
  • 12,888
  • 9
  • 86
  • 116
Yang C
  • 536
  • 5
  • 16
1

I had exactly the same issue as the original post.

Not sure the last comment is valid. It would make the HTML id attribute a run-time value and therefore cannot be referenced with a design time name.

I used the overload of DisplayFor which allows you to add new objects onto the data dictionary (ViewBag)

My model is a C# object called Project with various properties. In my view I have this:

@Html.DisplayFor(model => model.ProjectName, "StringDisplaySetHtmlID", new { HtmlID = "project-name" })

This is using a custom template called StringDisplaySetHtmlID and the last parameter adds a key value pair to the Viewbag.

My template file looks like this:

@model string
<span class = "display-field" id = "@(ViewBag.HtmlID)">@Model</span> 

I'm also setting a class here for styling purposes. I've used the key name HtmlID rather than just ID to avoid a potential common naming collision.

Now in my javascript I can pick up the span's content using the following jquery:

var projectName = $('#project-name').text()
1

The best way to build a display template that will output the following:

<span id="ElementsId">Element's value</span>

Would be this:

<span id="@Html.IdForModel()">@Html.DisplayTextFor(m => m)</span>

These helpers may not have existed when this question was first posted, but this builds on David's answer in two ways:

  1. Using @Html.DisplayTextFor(m => m) instead of @Model will still utilize data annotations while rendering the value instead of just essentially running ToString() on it.
  2. Using @Html.IdForModel() instead of @ViewData.ModelMetadata.PropertyName would be preferable in cases where the model is nested or repeated, and the ID is not going to simply be the property name.
Loren Paulsen
  • 8,960
  • 1
  • 28
  • 38