Using ViewModel information in an ASP.NET MVC 2 Editor or Display template - Jon Galloway

Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Editor and Display templates are a great new feature in ASP.NET MVC 2. They allow you to define a template which will be used for any datatype you’d like, and they can be set per-controller or site-wide.

The common scenario you may have seen is to set up a jQueryUI datapicker control for all DateTime editors site-wide. It’s really easy to set up – we create a /Views/Shared/DateTime.ascx file and add the following:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>

<%= Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line" }) %>

<script type="text/javascript">
    $(function () {
        $("#<%: ViewData.TemplateInfo.GetFullHtmlFieldId(String.Empty) %>").datepicker();
    });
</script>

Then we add the references to our jQueryUI js & css in our Site.master (or on pages as appropriate) and magically all our DateTime fields get datepickers.

Templates for custom objects

That’s great, but one of the more powerful uses of MVC2 templating is to create display or editor templates for your own business objects. For example, if you have a site that sells disco balls, you could create a discoball.ascx display template and use it whenever you display a discoball object (and of course, the same for editing as well).

I demonstrated an example of that in the MVC Music Store – there’s an Editor template for an Album, and it’s used in both the Edit and Create views.

The problem: DropDowns require ViewModels

Many editor templates will require a ViewModel, since your model object won’t contain all the possible values for dropdowns. For example here’s the Edit template for an Album:

The Album table holds an ArtistId and a GenreId, which link to the Artist and Genre tables. That means that our Album model knows about an ArtistId, but doesn’t have a list of all the Artists necessary to display in the dropdown. To do that, we need to introduce a ViewModel, which contains all the information our View will need:

using System.Collections.Generic;
using MvcMusicStore.Models;

namespace MvcMusicStore.ViewModels
{
    public class StoreManagerViewModel
    {
        public Album Album { get; set; }
        public List<Artist> Artists { get; set; }
        public List<Genre> Genres { get; set; }
    }
}

Note: This is a simple usage of a ViewModel. There are several usage patterns for ViewModels, and more advanced ViewModel patterns dictate that you never pass your domain entities to your view. That’s a good topic for another post, but worth mentioning in passing here.

Our StoreManagerController.Create() action can then return a ViewModel which holds an empty Album object, along with lists of Artists and Genres to be populated:

// 
// GET: /StoreManager/Create

public ActionResult Create()
{
    var viewModel = new StoreManagerViewModel
    {
        Album = new Album(),
        Genres = storeDB.Genres.ToList(),
        Artists = storeDB.Artists.ToList()
    };

    return View(viewModel);
}

The Problem: How do we pass additional information to a Template?

Until the RTM release of MVC 2, the above scenario wouldn’t work. You just couldn’t get at the additional ViewModel information – in this case, the Album and Genre lists – from your template files. There was no way to pass the information from your view to your template, which meant that you had to resort to stuffing the additional information into ViewData:

// 
// GET: /StoreManager/Create

public ActionResult Create()
{
    var album = new Album();
    // NOTE: Example! Don't copy / paste / deploy! 
    // Not the best way to do this!
    ViewData["Genres"] = storeDB.Genres.ToList();
    ViewData["Artists"] = storeDB.Artists.ToList();

    return View(album);
}

But I avoid ViewData as much as possible. It’s a weakly typed collection, and I really dislike returning a strongly typed object to the View and then sneakily passing additional information via ViewData.

The Solution: Templated Helper overrides that pass additional View Data

MVC 2 RTM included a nice new feature to solve this exact problem. From the MVC 2 RTM release notes:

Templated Helpers Allow You to Specify Extra View Data

ASP.NET MVC 2 now includes new overloads of the EditorFor and DisplayFor methods. These overloads contain a parameter that accepts an anonymous object that can be used to provide extra view data. The view data provided in this parameter is merged with any existing view data that is passed to the template.

Let’s look at the implementation in MVC 2 Source Code in System.Web.Mvc.Html.TemplateHelpers.TemplateHelper():

if (additionalViewData != null) {
    foreach (KeyValuePair<string, object> kvp in new RouteValueDictionary(additionalViewData)) {
        viewData[kvp.Key] = kvp.Value;
    }
}

That’s pretty straightforward – the common method used by both EditorTemplates and DisplayTemplates checks for additional view data and copies it to ViewData keyed with the name we provided. So, yes, it’s still using ViewData, but at least our Controller and View don’t need to know that.

Putting it all together

The View (/Views/StoreManager/Create.aspx)

We’ll use one of the EditorFor() overrides which allows passing additional view data. Note that these overloads use anonymous objects as dictionaries. This pattern is pretty common throughout the ASP.NET MVC framework, since it allows for very terse key-value pair definitions.

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcMusicStore.ViewModels.StoreManagerViewModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Create Album
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Create</h2>

    <% Html.EnableClientValidation(); %>

    <% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Create Album</legend>
        <%: Html.EditorFor(model => model.Album, new { Artists = Model.Artists, Genres = Model.Genres })%>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>

    <% } %>

    <div>
        <%:Html.ActionLink("Back to Albums", "Index") %>
    </div>


</asp:Content>

The Editor Template (/Views/Shared/EditorTemplates/Album.ascx)

This editor template is strongly typed to the Album, but is making use of the additional view data for the Html.DropDownList() calls.

<%@ Import Namespace="MvcMusicStore"%>

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MvcMusicStore.Models.Album>" %>

<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>

<p>
    <%: Html.LabelFor(model => model.Title)%>
    <%: Html.TextBoxFor(model => model.Title)%>
    <%: Html.ValidationMessageFor(model => model.Title)%>
</p>
<p>
    <%: Html.LabelFor(model => model.Price)%>
    <%: Html.TextBoxFor(model => model.Price)%>
    <%: Html.ValidationMessageFor(model => model.Price)%>
</p>
<p>
    <%: Html.LabelFor(model => model.AlbumArtUrl)%>
    <%: Html.TextBoxFor(model => model.AlbumArtUrl)%>
    <%: Html.ValidationMessageFor(model => model.AlbumArtUrl)%>
</p>
<p>
    <%: Html.LabelFor(model => model.Artist)%>
    <%: Html.DropDownList("ArtistId", new SelectList(ViewData["Artists"] as IEnumerable, "ArtistId", "Name", Model.ArtistId))%>
</p>
<p>
    <%: Html.LabelFor(model => model.Genre)%>
    <%: Html.DropDownList("GenreId", new SelectList(ViewData["Genres"] as IEnumerable, "GenreId", "Name", Model.GenreId))%>
</p>

We can continue to use the ViewModel and Controller Action code I showed earlier (repeated here for clarity):

StoreManagerViewModel.cs:

using System.Collections.Generic;
using MvcMusicStore.Models;

namespace MvcMusicStore.ViewModels
{
    public class StoreManagerViewModel
    {
        public Album Album { get; set; }
        public List<Artist> Artists { get; set; }
        public List<Genre> Genres { get; set; }
    }
}

StoreManagerController.cs - Create():

// 
// GET: /StoreManager/Create

public ActionResult Create()
{
    var viewModel = new StoreManagerViewModel
    {
        Album = new Album(),
        Genres = storeDB.Genres.ToList(),
        Artists = storeDB.Artists.ToList()
    };

    return View(viewModel);
}
Published Thursday, July 1, 2010 1:27 PM by Jon Galloway
Filed under: ,

Comments

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I know that it breaks the MVC pattern, but calling a static method directly from the view that returns the SelectList is so much easier, less error prone, and less code to type and validate.

<%: Html.DropDownList("ArtistId", Artist.GetSelectList(Model.ArtistId))%>

Friday, July 2, 2010 8:48 AM by edddy

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

<%= Html.EditorFor(model => model.Album, new { Artists = Model.Artists, Genres = Model.Genres } %>

I using VS2008 SP1 and Asp.Net MVC 2.

Error    1    'System.Web.Mvc.HtmlHelper<MvcMusicStore.ViewModels.StoreManagerViewModel>' does not contain a definition for 'EditorFor' and the best extension method overload 'System.Web.Mvc.Html.EditorExtensions.EditorFor<TModel,TValue>(System.Web.Mvc.HtmlHelper<TModel>, System.Linq.Expressions.Expression<System.Func<TModel,TValue>>, string)' has some invalid arguments

Error    2    Argument '3': cannot convert from 'AnonymousType#1' to 'string'

Please, help me.

Wednesday, October 20, 2010 5:52 AM by xuandungpy

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

This topic has been discussed on another web but not as detail as yours. great job.

Wednesday, March 9, 2011 12:54 PM by best pet supplies review

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I really liked your post.Really looking forward to read more. Awesome.

Tuesday, September 11, 2012 1:42 PM by kokt&#233;loz&#243;

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I appreciate you sharing this blog post.Thanks Again. Want more.

Wednesday, September 12, 2012 8:05 AM by stoffwechseldiaet

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I appreciate you sharing this article.Much thanks again. Really Great.

Wednesday, September 12, 2012 8:40 AM by turbulence training pdf

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Im obliged for the blog.Much thanks again.

Wednesday, September 12, 2012 3:46 PM by Kindle Opiniones

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Appreciate you sharing, great blog article. Much obliged.

Friday, September 14, 2012 5:52 AM by death after life

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I am so grateful for your blog. Will read on...

Friday, September 14, 2012 9:26 AM by multisearch

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Awesome blog article.Much thanks again. Really Cool.

Friday, September 14, 2012 9:34 AM by Christian Shopping

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Thanks a lot for the blog article.Thanks Again. Want more.

Friday, September 14, 2012 10:38 AM by best die cutting machine

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Really enjoyed this blog post. Fantastic.

Monday, September 17, 2012 6:47 AM by Fatcow Reviews

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Very good blog.Really looking forward to read more. Really Cool.

Monday, September 17, 2012 7:59 AM by rent trackless train

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Say, you got a nice post.Really looking forward to read more. Keep writing.

Monday, September 17, 2012 8:13 AM by piercings chicago

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Thanks again for the article. Awesome.

Thursday, September 20, 2012 4:10 AM by best canadian rock bands

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Thanks a lot for the article post.Thanks Again. Will read on...

Thursday, September 20, 2012 10:51 AM by Werewolves

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Very informative article. Want more.

Thursday, September 20, 2012 3:20 PM by over 50's dating

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Wow, great article post.Thanks Again. Keep writing.

Friday, September 21, 2012 6:32 AM by char broil gas grills

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Major thankies for the article.

Friday, September 21, 2012 7:41 PM by hell

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Very informative blog.Really looking forward to read more.

Friday, September 21, 2012 9:40 PM by utah restaurant

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I appreciate you sharing this blog article.Much thanks again. Really Great.

Friday, September 21, 2012 10:06 PM by nyc iphone unlock

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

A round of applause for your article post. Will read on...

Saturday, September 22, 2012 1:27 AM by what is ppc

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Thanks a lot for the blog.Really looking forward to read more. Fantastic.

Saturday, September 22, 2012 4:17 PM by consultancy

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Hey, thanks for the blog post.Really looking forward to read more. Really Great.

Sunday, September 23, 2012 3:21 AM by healthy recipes

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Muchos Gracias for your blog article.Thanks Again. Really Cool.

Sunday, September 23, 2012 8:56 AM by online business

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Enjoyed every bit of your blog post. Fantastic.

Sunday, September 23, 2012 10:46 AM by website design

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Very good blog article.Thanks Again.

Sunday, September 23, 2012 12:37 PM by karit&#233;

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I truly appreciate this blog article. Great.

Sunday, September 23, 2012 4:19 PM by New York City

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

A round of applause for your article post.Much thanks again. Really Great.

Sunday, September 23, 2012 6:10 PM by best home health service chicago

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I really liked your blog post.Thanks Again.

Monday, September 24, 2012 7:19 AM by Alexander Mans

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Hey, thanks for the blog article. Cool.

Tuesday, September 25, 2012 10:44 AM by security consulting

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Major thanks for the blog post. Great.

Tuesday, September 25, 2012 12:15 PM by healthy seeds

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I really liked your article post.Really looking forward to read more. Really Great.

Wednesday, September 26, 2012 4:53 AM by orange county windshield replacement

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I think this is a real great blog.Thanks Again. Keep writing.

Wednesday, September 26, 2012 5:31 PM by Peter Francis-Macrae

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Thanks for the article. Awesome.

Wednesday, September 26, 2012 9:18 PM by Peter Francis-Macrae

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

I really enjoy the blog.Much thanks again. Great.

Thursday, September 27, 2012 4:55 AM by gif maker

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Really appreciate you sharing this article.Much thanks again. Much obliged.

Thursday, September 27, 2012 9:38 PM by impressive adshel printing

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

This item is great for people w curly unruly hair. I have fine curly hair, just a lot of it - so sometimes products for curly thick (the folicle itself) do not give achieve the    

results I want for my hair. The great thing is you only need a couple of pumps (too much can make your hair kind of hard - as if you were using a gel) and give you super defined curls w/o using gels,    

hairsprays, individually twisting your curls, etc... It just gives you what you hope nature intended your hair to look like, w/o looking like you have a product in your hair - It has a nice mild smell and    

gives you soft and bouncy curls - I use it to style and comb my hair (when wet) and then finish with a bit of MoroccanOil and have hair that looks great all day long

Saturday, December 29, 2012 10:30 AM by Julia

# re: Using ViewModel information in an ASP.NET MVC 2 Editor or Display template

Attractive section of content. I simply stumbled upon your site

and in accession capital to claim that I get actually enjoyed account your weblog posts.

Any way I'll be subscribing to your feeds and even I success you get right of entry to constantly fast.

Monday, January 14, 2013 8:28 AM by Hostetler