in

Platinum Bay

Peace, Love, Team System, and Community

This Blog

Syndication


.NETicated

DevEvents: More .NET MVC HtmlHelpers

In my last post, I showed how I used an HtmlHelper to create an enumerable-based dropdown. In this post, I’ll share a few more HtmlHelpers I’ve created to make life easier, or the user experience better.

There are places in DevEvents, like the directory listings where it would not be optimal to display the whole text of a speaker or event description. In such cases, I use an HtmlHelper to truncate the text, and optionally append a ‘more info’ link. To make it even better, you might consider finding the next space (‘ ‘), and truncating there.

public static string TruncateText(this HtmlHelper helper, string text, int maxLength, string postFix)
{
if (text != null && text.Length > maxLength)
return text.Substring(0, maxLength) + postFix;

return text;
}

ResolveUrl is a very handy method, but it isn’t available everywhere I needed it to be, like inside other HtmlHelpers, so I created my own ResolveUrl HtmlHelper.

public static string ResolveUrl(this HtmlHelper helper, string url)
{
if (url.StartsWith("~/"))
{
string siteRoot = helper.ViewContext.HttpContext.Request.ApplicationPath;

if (siteRoot == string.Empty)
siteRoot =
"/";

return url.Replace("~/", siteRoot);
}
else
{
return url;
}
}

The HTML construct of ‘<label for’ is very helpful for individuals with accessibility issues and non-standard browsers. Instead of having to write out the whole HTML every time, I created an HtmlHelper:

public static string LabelFor(this HtmlHelper helper, string target, string text)
{
return String.Format("<label for='{0}'>{1}</label>", target, text);
}

One common website complaint is that text is not pluralized correctly. I created a very simple HtmlHelper to do just this:

public static string PluralizeText(this HtmlHelper helper, string singularText, string pluralText, int number)
{
if (number == 1)
return singularText;
else
return
pluralText;
}
You may wish to pass in HTML attributes to one or more of your HtmlHelpers, but how do you append them to the output? Here is a simple example showing how to append HTML attributes using a dictionary. Arguably this functionality could be an HtmlHelper itself. Notice it also utilizes the ResolveUrl HtmlHelper. (Updated: 1/14/2009: Removed some redundancy thank to Marc’s comments below
public static string Image(this HtmlHelper helper, string url, object htmlAttributes)
{
StringBuilder sb = new StringBuilder();
sb.Append(
"<img src=\"" + helper.ResolveUrl(url) + "\"");

IDictionary<string, object> attributes = new RouteValueDictionary(htmlAttributes);

if (attributes != null)
{
foreach (var item in attributes) { sb.Append(" " + item.Key + "=\"" + item.Value.ToString() + "\""); }
}

sb.Append(
" />");

return sb.ToString();
}

The introduction of anonymous types, generics, and other .NET 3.0 features also introduces some complexity when working with Nullable types. To facilitate these scenarios, I created the following HtmlHelper: (Updated 1/14/2009: Made it a generic method thanks to Liam’s comment below)

public static string FormatNullable<T>(this HtmlHelper helper, Nullable<T> nullable, string format, string emptyText) 
    where T : struct
{
    if (nullable.HasValue)
        return string.Format(format, nullable.Value);
    else
        return emptyText;
}

Hopefully you will find one or more of these HtmlHelpers helpful in your .NET MVC development. What custom HtmlHelpers do you use? Would you do any of these differently?

Published Jan 12 2009, 11:50 AM by Steve
Filed under: , ,

Comments

January 12, 2009 3:49 PM

WPF MouseEnter and MouseLeave loops in WPF [Via: Scott Hanselman ] Link Collections Interesting Finds:...

 

January 12, 2009 3:50 PM

Link Listing - January 11, 2009

 

January 12, 2009 9:49 PM

Good stuff Steve!

I especially like the ResolveUrl method... that can come in handy in a lot of places!

Where are you storing your single and plural text? Do you have an algorithm to pluralize a singular word? If so, it must be pretty smart :)

I like those Extensions... keep them coming!

A friend of mine has some more extensions listed on his website...  http://tinyurl.com/mvchelper

You can find out more about him here... http://twitter.com/mahdi

 

January 13, 2009 3:14 PM

That last method looks like a Reflector decompile... especially:

  string key = Convert.ToString((string)pair1.Key, CultureInfo.InvariantCulture);

Clearly, that's just:

 string key = (string)pair1.Key;

I would also worry that attribute values could sometimes be things that should be rendered in CurrentCulture.

 

January 13, 2009 4:23 PM

Nice artice,

If you used System.Web.Mvc.TagBuilder too you could cut back on the code even more, for instance:

       public static string Image(this HtmlHelper helper, string url, object htmlAttributes)

       {

           StringBuilder sb = new StringBuilder();

           TagBuilder tag = new TagBuilder("img");

           tag.MergeAttribute("src", helper.ResolveUrl(url));

           IDictionary<string, object> attributes = new RouteValueDictionary(htmlAttributes);

           tag.MergeAttributes<string, object>(attributes);

           return tag.ToString(TagRenderMode.SelfClosing);

       }

 

January 13, 2009 9:28 PM

I think FormatNullable could use generics to reduce the need for overloads.

public static string FormatNullable<T>(this HtmlHelper helper, Nullable<T> nullable, string format, string emptyText)

{

   if (nullable.HasValue)

       return string.Format(format, nullable.Value);

   else

       return emptyText;

}

 

January 14, 2009 12:58 AM

@Elijah: I don't have an algorithm like that. In the case of 'one fish, two fish', I just wouldn't use the HtmlHelper. Great links too!

@Marc: I removed the redundancy, thanks!

@Paul: I was not aware of TagBuilder. It looks like it'll definitely help remove unnecessary code in places.

@Liam: As listed, you will receive an error: "The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>". I appended "where T : struct", and it is working fine. Thanks!

 

October 8, 2009 7:54 AM

John
 

Leave a Comment

(required )  
(optional )
(required )  
Add

About Steve

Steve Andrews is a Team System MVP and INETA Speaker, and has been working as a developer for more than 9 years. During this time, he has designed and developed applications in such widely varying areas as trust accounting, medical information management, supply chain management, and retail systems. Steve is also an MCP, ICSOO, Speaker Liaison for the Philly .NET User Group, and community fanatic.
Powered by Community Server (Commercial Edition), by Telligent Systems
© Platinum Bay | Some Rights Reserved Creative Commons License

Disclaimer: The information in this weblog is provided "AS IS" with no warranties, and confers no rights. This weblog does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion. Feel free to challenge me, disagree with me, or tell me I'm completely nuts in the comments section of each blog entry, but I reserve the right to delete any comment for any reason whatsoever (abusive, profane, rude, or annonymous comments) - so keep it polite, please.