Showing posts with label html helpers. Show all posts
Showing posts with label html helpers. Show all posts

Wednesday, October 12, 2011

MVC3 Helper methods supporting Linq Expressions

I was a bit frustrated with the .DropDownFor() extension on the HtmlHelper class.  There was no access to the OPTION tags, and I've never been a fan of the SelectList object.  I wanted to put some tool tip text (using the title attribute) on the options to provide more context in the selection.  Of course there was no way to do that with the .DropDownFor() helper method.  So, time to roll my own.

Only thing was, I'd never written an extension that used a Linq expression before, so it took a little research.  Finally I found this post (I heart StackOverflow) and piecing it together from there, came up with this joker:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web;


namespace System.Web.Mvc
{
public static class MoreHelpers
{
public static HtmlString SelectFor<TModel, TProperty, TListItem>(
this HtmlHelper<TModel> htmlHelper, 
Expression<Func<TModel, TProperty>> expression,
IEnumerable<TListItem> enumeratedItems,
string idPropertyName,
string displayPropertyName,
string titlePropertyName,
object htmlAttributes
)
 where TModel : class
{
//initialize values
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var propertyName = metaData.PropertyName;
var propertyValue = metaData.Model.ToStringOrEmpty();
var enumeratedType = typeof(TListItem);

//build the select tag
var returnText = string.Format("<select id=\"{0}\" name=\"{0}\"", HttpUtility.HtmlEncode(propertyName));
if (htmlAttributes != null)
{
foreach (var kvp in htmlAttributes.GetType().GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(htmlAttributes, null)))
{
returnText += string.Format(" {0}=\"{1}\"", HttpUtility.HtmlEncode(kvp.Key),
HttpUtility.HtmlEncode(kvp.Value.ToStringOrEmpty()));
}
}
returnText += ">\n";


//build the options tags
foreach (TListItem listItem in enumeratedItems)
{
var idValue = enumeratedType.GetProperties()
.FirstOrDefault(p => p.Name == idPropertyName)
.GetValue(listItem, null).ToStringOrEmpty();
var titleValue = enumeratedType.GetProperties()
.FirstOrDefault(p => p.Name == titlePropertyName)
.GetValue(listItem, null).ToStringOrEmpty();
var displayValue = enumeratedType.GetProperties()
.FirstOrDefault(p => p.Name == displayPropertyName)
.GetValue(listItem, null).ToStringOrEmpty();
returnText += string.Format("<option value=\"{0}\" title=\"{1}\"",
HttpUtility.HtmlEncode(idValue), HttpUtility.HtmlEncode(titleValue));
if (idValue == propertyValue)
{
returnText += " selected=\"selected\"";
}
returnText += string.Format(">{0}</option>\n", displayValue);
}


//close the select tag
returnText += "</select>";
return new HtmlString(returnText);
}


public static string ToStringOrEmpty(this object target)
{
if (target == null) return string.Empty;
return target.ToString();
}
}
}


Works like a champ!