1

I have a display for a collection of "SomeObject"

public List<SomeObject> SomeObjects

@Html.DisplayFor(m => m.SomeObjects)

This all works fine.. Then I had a requirement that meant I would need a second different display template for the same collection..

@Html.DisplayFor(m => m.SomeObjects, "NameOfTemplate")

I get the below message when I do this.. I have used named display templates before, but maybe it only works for primitive types - strings etc?

'System.Collections.Generic.List1[SomeObject]', but this dictionary requires a model item of type 'SomeObject'.

Adding code as request

"Test" DisplayTemplate

@model ViewModels.SomeObject

<p class="Namme">
    <span>@Model.Name</span>
</p>

SimpleViewModel

 public class SomeObject
    {
        public string Name { get; set; }
    }

Property in ParentViewModel

public List<SomeObject> SomeObjects { get; set; }

Cshtml file..

@Html.DisplayFor(m => m.SomeObjects, "Test")

To me its a simple question, can a named template be used with a collection or not? Is it another limitation of mvc..

Cheers, John

John
  • 698
  • 1
  • 11
  • 22
  • Make sure the model in the Display template is of the same type your passing in via the DisplayFor razor extension. Seems like it isnt a generic list in your Display Template. For example in your template: '@model IList' opposed to '@model SomeObject' – gdp Nov 13 '13 at 14:26
  • I tried what you suggested and it didn't work. My understanding is that model for the displayTemplates should be the single and not the collection.. Here is what I tried and the error @model IList HttpCompileException was unhandled by user code. "External component has thrown an exception." – John Nov 13 '13 at 14:42
  • Can you post full code, including the Template. Basically whatever you are passing through via the Display For, that should be the model type for the Display Template. Try putting a '@Html.DisplayFor(m => m .SomeObjects.First(), "TemplateName")'. Seems like your just passing in the incorrect model type. Include the model code for the calling CSHTML page too. – gdp Nov 13 '13 at 14:46

2 Answers2

2

Yes you are passing a list of SomeObject to your display template, when it is expecting:

@model ViewModels.SomeObject

You either need to change the template to something like this and accept a list as the view model:

@model IList<ViewModels.SomeObject>

@foreach (var item in Model) {
<p class="Namme">
    <span>@item</span>
</p>
}

Or change what you are passing into the Display Template in the parent CSHTML file and make it a single object of SomeObject something like this:

public List<SomeObject> SomeObjects

@foreach (var item in Model.SomeObjects) {
    Html.DisplayFor(item, "TemplateName")
}

Its hard to answer because im not sure what your trying to achieve, and what SomeObject is, but this should point you in the right direction.

gdp
  • 8,032
  • 10
  • 42
  • 63
  • Thanks gdp.. Its a limitation of mvc so.. As passing the list(when not a named display template works fine, mvc does the looping for me) Once you use a named template, it will pass the collection, so yes the model will need to be the collection, hence needing the for loop within. Pointless to me so, as I had a for loop in my calling code, I was wanting to use the display template so that I could eliminate it. As mentions once Its not a named template it works fine.. ah well. live and learn :) – John Nov 13 '13 at 15:11
  • Its just that you had the incorrect model type in your custom Display Template. Changing this to a list in the template is what MVC will be doing anyway under the hood by solely using this: '@Html.DisplayFor(m => m.MyCollection)'. – gdp Nov 13 '13 at 15:14
  • true, but inside my template if I try and access the elements of the object I need the for loop.. what I wanted to avoid.. when its not a named template i dont need a loop. thats the main difference for me.. – John Nov 13 '13 at 15:16
  • 2
    Yeh you cant avoid that unfortunately, if you want more granular control then you have to loop the model. – gdp Nov 13 '13 at 15:17
0

The type of SomObjects is List<SomeObjects> so the view template must have a matching model:

@model `ICollection<ViewModels.SomeObject>`

I prefer to not restrict the view to the concrete List<> class but rather use an interface.

That also means that you have to adjust your template to use a loop to iterate through the items in the collection.

Anders Abel
  • 67,989
  • 17
  • 150
  • 217
  • Anders, If I do that, I would need to iterate over it with a for loop. The point of me using the template was to remove the for loop from the calling page.. By putting the single Object as the model I dont need the loop and mvc takes care of the iterating.. This all works fine, until I try a named template which is what my question is about, as I have got many working with collections.. Related to this post.. http://stackoverflow.com/questions/8002059/asp-net-mvc-display-template-for-a-collection – John Nov 13 '13 at 15:07
  • 1
    The problem is that you can only tell MVC what template to use for the *entire collection* then it uses its internal logic to find the template for each item. If that is what you want to control you're probably out of luck as I don't know of a way to pass a display template to that second lookup step. – Anders Abel Nov 13 '13 at 15:11