Rajeeshcv.com

Sharing my knowledge

Asp.Net MVC - Fluent Html helper for FlexiGrid

There are so many free JQuery Grid plugins out there, in that I liked FlexiGrid just because of it’s look and style. In order to use it in your MVC application you may have to put the Javascript code into your view, which requires the property names of your model in order to generates the Grid columns as well the search options etc… as everybody knows when you deal with hard coded string as the property names in any code, it is error prone.

In order to avoid this problem I thought of creating a html extension which is tightly coupled with your data that is going to bound to the Grid. Which helps the developer from writing any javascript codes(I know those who hates(not me! :)) writing Javascript code like this extension).

This project has been uploaded to - http://code.google.com/p/mvc-fluent-jquery-plugin-controls/. You could find more details from there.


JQueryUI Datepicker in ASP.Net MVC

Datepicker is nice and cool plugin for displaying the calendar with ease. It is very easy to use JQuery plugin, it comes as part of JQueryUI library, so if you want to use this – first download JQueryUI from http://jqueryui.com/download and also download JQuery(http://docs.jquery.com/Downloading_jQuery) if you haven’t done yet. For e.g. if you have a form like one below

<% using(Html.BeginForm()){%>
  <fieldset>
    <legend>Event Information</legend>
     <p>
        <label for="EventName">Event Name:</label>
        <%= Html.TextBox("EventName")%>
            </p>
            <p>
            <label for="StartDate">Start Date:</label>
            <%= Html.TextBox("StartDate")%>
            </p>
            <p>
            <label for="EndDate">End Date:</label>
            <%= Html.TextBox("EndDate")%>
            </p>
            <p>
                <input type="submit" value="Save" />
            </p>
  </fieldset>
<% }%>

and you want to attach datepicker to “StartDate” and “EndDate” input fields, what you needs to do is call the datepicker function on the these input field selector like below.

<script language="javascript">
    $(document).ready(function() {
    $('#StartDate').datepicker();
    $('#EndDate').datepicker();
    });
</script>

This works fine as we expected :)

Difference in Date format patterns

Consider a scenario where your MVC application supports localization, then the selected date displayed in the input fields also should display the in the same date format of the current culture(This format could be custom one or default one). This leads to you another issue – Datepicker plugin given by the JQueryUI supports different date formats, but it is different from one that is available in .NET. For e.g. in order to display a long day name (“Thursday”) .NET uses “dddd” its equivalent in Datepicker is “DD”. In order to solve this disparity between the .NET world and Datepicker world, I have created a html helper function, which could generate the Datepicker format from a .Net date format.

/// <summary>
/// JQuery UI DatePicker helper.
/// </summary>
public static class JQueryUIDatePickerHelper
{
    /// <summary>
    /// Converts the .net supported date format current culture format into JQuery Datepicker format.
    /// </summary>
    /// <param name="html">HtmlHelper object.</param>
    /// <returns>Format string that supported in JQuery Datepicker.</returns>
    public static string ConvertDateFormat(this HtmlHelper html)
    {
        return ConvertDateFormat(html, Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern);
    }

    /// <summary>
    /// Converts the .net supported date format current culture format into JQuery Datepicker format.
    /// </summary>
    /// <param name="html">HtmlHelper object.</param>
    /// <param name="format">Date format supported by .NET.</param>
    /// <returns>Format string that supported in JQuery Datepicker.</returns>
    public static string ConvertDateFormat(this HtmlHelper html, string format)
    {
        /*
         *  Date used in this comment : 5th - Nov - 2009 (Thursday)
         *
         *  .NET    JQueryUI        Output      Comment
         *  --------------------------------------------------------------
         *  d       d               5           day of month(No leading zero)
         *  dd      dd              05          day of month(two digit)
         *  ddd     D               Thu         day short name
         *  dddd    DD              Thursday    day long name
         *  M       m               11          month of year(No leading zero)
         *  MM      mm              11          month of year(two digit)
         *  MMM     M               Nov         month name short
         *  MMMM    MM              November    month name long.
         *  yy      y               09          Year(two digit)
         *  yyyy    yy              2009        Year(four digit)             *
         */

        string currentFormat = format;

        // Convert the date
        currentFormat = currentFormat.Replace("dddd", "DD");
        currentFormat = currentFormat.Replace("ddd", "D");

        // Convert month
        if (currentFormat.Contains("MMMM"))
        {
            currentFormat = currentFormat.Replace("MMMM", "MM");
        }
        else if (currentFormat.Contains("MMM"))
        {
            currentFormat = currentFormat.Replace("MMM", "M");
        }
        else if (currentFormat.Contains("MM"))
        {
            currentFormat = currentFormat.Replace("MM", "mm");
        }
        else
        {
            currentFormat = currentFormat.Replace("M", "m");
        }

        // Convert year
        currentFormat = currentFormat.Contains("yyyy") ? currentFormat.Replace("yyyy", "yy") : currentFormat.Replace("yy", "y");

        return currentFormat;
    }
}

So how we could make use this helper method, just replace the datepicker initialization code we have written earlier with this

<script language="javascript">
    $(document).ready(function() {
    $('#StartDate').datepicker({ dateFormat: '<%= Html.ConvertDateFormat() %>' });
    $('#EndDate').datepicker({ dateFormat: '<%= Html.ConvertDateFormat() %>' });
    });
</script>

Hope this helps.


ASP.Net MVC - Conditional Rendering

We come across situations like rendering elements based on the conditions in Model. For example, in the view if we want to show a TextBox if some property is true. A normal way of doing this is like below

<% if (this.Model.Exists)
      {%>
      <%= Html.TextBox("Test") %>
   <% } 

This looks like old classic asp style, and when it comes to code maintenance this will be a pain. So a clean way is to use an Html helper to generate this

  <%= Html.If(this.Model.Exists, action => action.TextBox("Name")) %>

which looks cleaner than the old one. Source code for this helper method is

public static string If(this HtmlHelper htmlHelper, bool condition, Func<HtmlHelper, string> action)
{
    if (condition)
    {
        return action.Invoke(htmlHelper);
    }

    return string.Empty;
}

What about IfElse condition, we could write another helper method for that

public static string IfElse(this HtmlHelper htmlHelper, bool condition, Func<HtmlHelper, string> trueAction, Func<HtmlHelper, string> falseAction)
{
    if (condition)
    {
        return trueAction.Invoke(htmlHelper);
    }

    return falseAction.Invoke(htmlHelper);
}

Ok, now we got a conditionally rendered element, sometimes we may have to put a wrapper around this element. So I have written another Html helper method which will help you to put any html element around a particular element.

public static string HtmlTag(this HtmlHelper htmlHelper, HtmlTextWriterTag tag, object htmlAttributes, Func<HtmlHelper, string> action)
{
    var attributes = new RouteValueDictionary(htmlAttributes);

    using (var sw = new StringWriter())
    {
        using (var htmlWriter = new HtmlTextWriter(sw))
        {
            // Add attributes
            foreach (var attribute in attributes)
            {
                htmlWriter.AddAttribute(attribute.Key, attribute.Value != null ? attribute.Value.ToString() : string.Empty);
            }

            htmlWriter.RenderBeginTag(tag);
            htmlWriter.Write(action.Invoke(htmlHelper));
            htmlWriter.RenderEndTag();
        }

        return sw.ToString();
    }

    return string.Empty;
}

An overloaded version which doesn’t accept HtmlAttributes as parameter

public static string HtmlTag(this HtmlHelper htmlHelper, HtmlTextWriterTag tag, Func<HtmlHelper, string> action)
{
    return HtmlTag(htmlHelper, tag, null, action);
}

Below are some examples of using these helpers.

<%= Html.HtmlTag(HtmlTextWriterTag.Div, action => action.ActionLink("Without attributes","About") ) %>

<%= Html.HtmlTag(HtmlTextWriterTag.Div, new { name = "wrapper", @class = "styleclass" }, action => action.ActionLink("With Attributes", "About")) %>

<%= Html.HtmlTag(HtmlTextWriterTag.Div, null, action => action.ActionLink("Null attributes", "About")) %>
  
<%= Html.IfElse(this.Model.Exists, trueAction => trueAction.Encode("Sample"), falseAction => falseAction.TextBox("SampleName")) %>
  
<%--
Nesting 
<div>
   <span>
       <a href="/Home/About">About</a>
   </span>
</div> 
--%>
<%= Html.If(this.Model.Exists, 
    div => div.HtmlTag(HtmlTextWriterTag.Div,
        span => span.HtmlTag(HtmlTextWriterTag.Span,
anchor => anchor.ActionLink("About", "About"))
)) %>

Hope this will help you.


ASP.Net MVC - Conditional rendering Partial Views

Update : Later I found a cleaner and simple approach to do the same – read this post ASP.Net MVC – Conditional rendering Partial Views with Action<T> delegate

Following my previous post about Conditional Rendering, one of my colleague asked me how to render the partial view based on a condition.

Normal way of doing this is

<p>Normal partial rendering based on condition</p>           
<% if(this.Model.Exists)
 {
     Html.RenderPartial("MyPartialView");
 } %>

I am not sure about any other technique for rendering partial view conditionally other than this (correct me if I am wrong :) ).

Then I thought about copying the pattern I have used in my previous post and came up with this code which could conditionally render partial views and you could use the Html extension like below, which more clean than the previous

<% Html.PartialIf(this.Model.Exists, "MyPartialView"); %>

Below is the Html extension I have created

public static void PartialIf(this HtmlHelper htmlHelper, bool condition, string viewName)
       {
           if (condition)
           {
               RenderPartialInternal(
                   htmlHelper.ViewContext, 
                   htmlHelper.ViewDataContainer, 
                   viewName,
                   htmlHelper.ViewData, 
                   null, 
                   ViewEngines.Engines);
           }
       }

public static void PartialIf(this HtmlHelper htmlHelper, bool condition, string viewName, ViewDataDictionary viewData)
       {
           if (condition)
           {
               RenderPartialInternal(
                   htmlHelper.ViewContext,
                   htmlHelper.ViewDataContainer,
                   viewName,
                   viewData,
                   null,
                   ViewEngines.Engines);
           }
       }

public static void PartialIf(this HtmlHelper htmlHelper, bool condition, string viewName, object model)
       {
           if (condition)
           {
               RenderPartialInternal(
                   htmlHelper.ViewContext,
                   htmlHelper.ViewDataContainer,
                   viewName,
                   htmlHelper.ViewData,
                   model,
                   ViewEngines.Engines);
           }
       }

public static void PartialIf(this HtmlHelper htmlHelper, bool condition, string viewName, object model, ViewDataDictionary viewData)
       {
           if (condition)
           {
               RenderPartialInternal(
                   htmlHelper.ViewContext,
                   htmlHelper.ViewDataContainer,
                   viewName,
                   viewData,
                   model,
                   ViewEngines.Engines);
           }
       }

And here is the helper method I have used in the about extension ( most of the code snippet is taken from the MVC method Html.Renderpartial(…), thanks to open source )

internal static IView FindPartialView(ViewContext viewContext, string partialViewName, ViewEngineCollection viewEngineCollection)
{
    var result = viewEngineCollection.FindPartialView(viewContext, partialViewName);
    if (result != null)
    {
        if (result.View != null)
        {
            return result.View;
        }
    }

    throw new InvalidOperationException("Partial view not found");
}

internal static void RenderPartialInternal(ViewContext viewContext, IViewDataContainer viewDataContainer, string partialViewName, ViewDataDictionary viewData, object model, ViewEngineCollection viewEngineCollection)
{
    if (String.IsNullOrEmpty(partialViewName))
    {
        throw new ArgumentException("PartialViewName can't be empty or null.");
    }

    ViewDataDictionary newViewData = null;

    if (model == null)
    {
        newViewData = viewData == null ? new ViewDataDictionary(viewDataContainer.ViewData) : new ViewDataDictionary(viewData);
    }
    else
    {
        newViewData = viewData == null ? new ViewDataDictionary(model) : new ViewDataDictionary(viewData) { Model = model };
    }

    var newViewContext = new ViewContext(viewContext, viewContext.View, newViewData, viewContext.TempData);
    var view = FindPartialView(newViewContext, partialViewName, viewEngineCollection);
    view.Render(newViewContext, viewContext.HttpContext.Response.Output);
}

 

Hope this helps


ASP.Net MVC &ndash; Conditional rendering Partial Views with Action&lt;T&gt; delegate

This is an update to my previous post regarding conditional rendering partial views, in that I used the internal implementation of the Html.RenderPartail(…) method to create the Html extension. Later I found a simple way to achieve the same using Action<T> delegate

<p>Partial rendering with Action Methods</p>        
<% Html.PartialIf(this.Model.Exists, html => html.RenderPartial("MyPartialView")); %>

If you look at the “PartialIf” implementation, it is simple, cleaner than the previous technique I have mentioned in my post.

public static void PartialIf(this HtmlHelper htmlHelper, bool condition, Action<HtmlHelper> action)
{
    if (condition)
    {
        action.Invoke(htmlHelper);
    }
}

That’s it :)


MVC - Rendering view elements in a specified order

In my current project, I had to render elements in the view based on a setting provided by the model(basically it is a configurable thing). Few clients need view element to be rendered in a particular order and few others in a different way. What we did was, saved this elements order in a settings file which could be changed based on the clients. Then created an extension to render this based on the order.

This is what was I was trying to explain. for  Client 1 the “Login section” to be displayed first followed by “Password reminder section

image

For Client 2 , these sections needs be ordered differently

image

In order to achieve this, I came up with an HtmlHelper extension

/// <summary>
/// Renders the render items in the provided sequence order.
/// </summary>
/// <param name="htmlHelper">The HTML helper which is extended.</param>
/// <param name="sequenceOrder">The order in which items to be rendered. Sequence starts at an index of 0.</param>
/// <param name="renderItems">The items to be rendered in order.</param>
/// <remarks>
/// Values in the sequence order should match with the total number of render items. 
/// Invalid sequnce numbers are ignored.
/// </remarks>
public static void OrderBy(this HtmlHelper htmlHelper, int[] sequenceOrder, params Action<HtmlHelper>[] renderItems)
{
    if (sequenceOrder != null && renderItems != null)
    {
        foreach (var sequnce in sequenceOrder)
        {
            // CHeck whether the sequence is with inthe bounds
            if (sequnce < renderItems.Length && sequnce >= 0)
            {
                renderItems[sequnce].Invoke(htmlHelper);
            }
        }
    }
    else if (renderItems != null)
    {
        // If the sequence order is not provided, render it in normal order in which items are declared.
        foreach (var renderItem in renderItems)
        {
            renderItem.Invoke(htmlHelper);
        }
    }
    else
    {
        // Do Nothing
    }
}

In the view, you could do

<% Html.OrderBy(this.Model.LoginDisplayOrder, (html) => { %>
    <div class="container"></div>                
    <% Html.RenderPartial("LoginSection", this.Model); %>
<% }, (html) => { %>
    <div class="container"></div>
    <% Html.RenderPartial("ReminderPassword", this.Model); %>
<% }); %>

Here Model.LoginDisplayOrder is just an array of integers in which the items to be rendered. Hope this will help.