2

I am having an issue with a custom display template in an MVC 5 application. I have a viewmodel that contains a complex type that I wanted to reuse. I created the DisplayTemplates folder and placed a partial view that follows the correct naming convention. Everything seems to work correctly and the partial view gets called but nothing renders on the browser.

I have checked the rendered html to make sure it wasn't being hidden or displayed funny but there is literally nothing rendered in the html output. Please see below for relevent screenshots. What am I doing wrong? Thanks.

Folder Structure

project structure

Here is the initial view. The viewmodel has a list of AvailableOption. The foreach calls the displayfor

@model CustomerWebPortal.ViewModels.OrderVehicle

@using (Html.BeginForm("CreateOrder", "Home"))
{
    <h2>@Html.DisplayFor(x => x.DisplayName)</h2>

    <div class="description">
        <ul>
            @Html.Raw(Model.Description)
        </ul>
    </div>

    <h3>Available Options</h3>
    <hr />

    <div>
        @foreach (var option in Model.AvailableOptions)
        {
            Html.DisplayFor(x => option, "AvailableOption");
        }
    </div>

    <h3>Customer</h3>
    <hr />
    
    <div class="customerInfo">
        @Html.LabelFor(x => x.Customer)
        @Html.TextBoxFor(x => x.Customer)
        @Html.ValidationMessageFor(x => x.Customer)
    </div>

    <div class="actions">
        <input type="submit" value="Place Order" />
    </div>

    @Html.HiddenFor(x => x.VehicleId)
    @Html.HiddenFor(x => x.Price)
}

Here is the partial view for the complex type

@model CustomerWebPortal.ViewModels.AvailableOption

<div class="row-fluid padtopbottom5">
    <div class="span6">
        <div class="row-fluid">
            <div class="span4">
                @Html.CheckBoxFor(x => x.Selected)
            </div>
        </div>
    </div>

    <div class="span6">
        <div class="row-fluid">
            <div class="span4">
                <h3>@Html.DisplayFor(x => x.DisplayName)</h3>

                <ul>
                    @Html.Raw(Model.Description)
                </ul>

                <p><strong>@Html.DisplayFor(x => x.Price)</strong></p>
            </div>
        </div>
    </div>
</div>

Here is the foreach that calls the displayfor for the complex type

enter image description here

Here is the resulting rendered HTML

enter image description here

I have created a small test project that reproduces the error if anyone wants to take a look. Sample Project

Clayton Page
  • 95
  • 1
  • 13
  • 1
    1) Which views are you showing us here? 2) Did you include the `@model IEnumerable` declaration? 3) Move your folder to `Views/Shared/DisplayTemplates`. – Jasen Feb 01 '16 at 18:05
  • Is the second image the content for your display template ? Also, try to post real code than images. – Shyju Feb 01 '16 at 18:18
  • Why are you placing a subfolder inside the Home Views Folder, if you are doing that you need to create a route definition for that, I would suggest to avoid this. – COLD TOLD Feb 01 '16 at 18:18
  • 1
    Does it just need an "@" in front of the Html helper? I'm pretty new to MVC, but I created a similar loop using Raw and some tags just for testing.. It had the same behavior you describe with "Html.Raw..." but it worked with "@Html.Raw..." – Aaron Feb 01 '16 at 18:26
  • My testing seems to disagree, but again, I'm a beginner. Perhaps Raw is treated differently than DisplayFor or something. – Aaron Feb 01 '16 at 18:30
  • @Aaron I decided to test both ways out and it turns out you were right. My guess is Clayton was thinking along the same lines I was. – Drew Kennedy Feb 01 '16 at 18:36
  • @Aaron Or you're just smarter than you think. :p I'd put your suggestion as an answer. :) – Drew Kennedy Feb 01 '16 at 18:38
  • Okay. Sorry for the images. I have edited my question to include actual code. Jason: I intially had my view in the Shared/DisplayTemplates folder but the view never got called let alone loaded. It serves my purposes to have it in the same view folder as the controller since it will never get called from anywhere else. COLD TOLD: All the examples and MS documentation say that this is how the templating works and no routes are required. As I stated it does find and call my view it just doesn't render it. – Clayton Page Feb 01 '16 at 21:27
  • Aaron: You need the @ only if the code is not in a code block. The call happens from inside the call block of the foreach so it does require one. I'll give the raw a shot and see if that helps. Thanks for the imput so far guys. – Clayton Page Feb 01 '16 at 21:31
  • Clayton I wasn't suggesting using a raw. Just test it with an @Html.DisplayFor... see my answer below, look at my outputs. It is pretty much exactly your problem...I used Raw because it was easier than creating a class, but the output is identical to your issue. – Aaron Feb 01 '16 at 21:40
  • Aaron, No worries. I understand what you were getting at. Unfortunately the raw didn't work for me. I think it's the complex type. Everything I've read says this should work fine so I'm not sure what I'm missing. The weird thing is that there's no error. It calls the view (I can step through the breakpoints) but does show anything in the browser. Thanks though :D – Clayton Page Feb 01 '16 at 21:58
  • If you put a breakpoint in your loop is it hitting it? As long as it's hitting it, I'm willing to bet that's the issue. Just give it a try.. someone else said the same thing about being in the code block, but they tested it and verified. It needs the @ – Aaron Feb 01 '16 at 21:59

2 Answers2

2

This is in the comments of the question, but I wrote a small test app using Html.Raw, and apparently it should also fix your case. It just needs an "@" in front of the Html.DisplayFor

ViewModel (in my case, junk data for you)

public class IndexViewModel
{
    private IEnumerable<string> _avlOpt;

    public IEnumerable<string> AvailableOptions
    {
        get { return _avlOpt; }
        set { _avlOpt = value; }
    }

    public IndexViewModel()
    {
        List<string> lstString = new List<string>();
        for (int i=1;i<5;i++)
        {
            lstString.Add(@"<h" + i.ToString() + ">Test</h" + i.ToString() + ">");
        }
        AvailableOptions = lstString;
    }
}

View

 test<br/>
 @foreach (var option in Model.AvailableOptions)
 {
   @Html.Raw(option);
 }
<br/>end test

View Result (Source - WITHOUT "@" - Html.Raw(option))

<div>
test<br/>
<br/>end test
</div>

View Result (Source - WITH "@" - @Html.Raw(option))

<div>
test<br/>
<h1>Test</h1><h2>Test</h2><h3>Test</h3><h4>Test</h4>    <br/>end test
</div>
Aaron
  • 1,313
  • 16
  • 26
  • This didn't work for me either. I think the difference is that your collection is a collection of primitive types and my availableoptions is a complex type. I have created a test project that reproduces the error. The link is in the main question. Thanks. – Clayton Page Feb 01 '16 at 21:53
  • The @ or using raw? I'm not saying to use Raw. I'm just asking you to put an @ in front of the Html.DisplayFor. I understand that it's in the code block. Just try it. Ignore the raw. Just put @ in front and try it. – Aaron Feb 01 '16 at 22:07
  • Ahh... you sir are correct. Strange because I was sure you didn't need it in the code block. Either way that fixed it. Thanks for your time. – Clayton Page Feb 01 '16 at 22:12
  • 2
    I think something changed in the Razor engine. Someone else mentioned the code block as well... It's apparent that used to be the way. – Aaron Feb 01 '16 at 22:16
1

If you're a dunce, like me, be sure you didn't create a blank DisplayTemplate for the value type.

In my case I was experimenting with something and got distracted, leaving an empty file in the DisplayTemplates folder named string.cshtml and spent the next hour upon return trying to figure out why my values stopped displaying.

Don't do that

Kevin R.
  • 3,571
  • 1
  • 19
  • 29