Wednesday, October 2, 2013

Create Custom Calendar in MVC

There are several plugins out there that can help you to create a calendar in MVC, JQuery, and other languages, but one disadvantage to all of these is a lack of customization.  In searching the web, I noticed that not many articles have been written about this topic, so here's one example.

This article will help you get started in creating a fully customizable HtmlHelper method to use throughout your application in MVC.  I prefer MVC4, but it will work with version 3 as well.

First, create a static class and name it whatever.  Mine is called DataControls, but it isn't important.  The only reason for the static method is so that you can use it as an MVC helper class in your view.

The class looks like this:

using System;
using System.Globalization;
using System.Text;
using System.Web.Mvc;
public static class DataControls
    {
        public enum DayFormat
        {
            Long, Medium, Short
        }

        public static MvcHtmlString Calendar(
  this HtmlHelper helper,
  DayFormat dayFormat,
  int month, int year)
        {
            DateTime today = DateTime.Now;
            int daysInMonth = DateTime.DaysInMonth(year, month);
            string[] dayNames = new string[] { };
            switch (dayFormat)
            {
                case DayFormat.Medium:
                    dayNames = new string[] { "Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat" };
                    break;
                case DayFormat.Short:
                    dayNames = new string[] { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" };
                    break;
                case DayFormat.Long:
                    dayNames = new string[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
                    break;
                default:
                    throw new Exception("Please specify a Day Format.");
            }
            StringBuilder calendar = new StringBuilder();
            calendar.Append(string.Format("

", "calendar"));

            calendar.Append("");
            calendar.Append(" ");
            for (int i = 0; i < dayNames.Length; i++)
            {
                calendar.Append(string.Format("{0}", dayNames[i]));
            }
            calendar.Append("
");            calendar.Append("
");            calendar.Append("");
            for (int i = 1; i <= 42; i++)
            {
                if (i % 7 == 1)
                {
                    calendar.Append(" ");
                }
                calendar.Append("");
                DateTime firstDay = new DateTime(year, month, 1);
                int firstDayOfWeek = (int)CultureInfo
        .InvariantCulture.Calendar.GetDayOfWeek(firstDay);
                if (i > firstDayOfWeek && (i - firstDayOfWeek) <= daysInMonth)
                {
                    calendar.Append(i - firstDayOfWeek);
                }
                calendar.Append("
");                if (i % 7 == 7)
                {
                    calendar.Append("
");                }
            }
            calendar.Append("
");            calendar.Append("
");            return MvcHtmlString.Create(calendar.ToString());
        }
    }

In a nutshell, we are creating a table that allows us to specify a format for month names, and then doing a loop to determine what day of week each day falls on, as well as how many days occur in the selected month and year.  If you don't care about the format of the days, you don't have to use the enum, but I like to allow for customization.

Once this is created, you can simply call this function inside of your razor view by calling:

(This would generate a calendar for January of 2013)
@Html.Calendar(DataControls.DayFormat.Medium, 1, 2013)

Obviously, you'd want to create a filter mechanism for displaying months and years to the user so they could select a month and year, but that is outside of the scope of this article.  Personally, I created an array and displayed dropdowns in my page for them to select from, but just as easily, you could create custom links for them to select from as well.  Use your imagination.

Good luck with this, and if you have any questions, feel free to contact me via my homepage at: Joshua Blackstone.Com or comment below.

Thanks.

Thursday, August 15, 2013

MVC Pass Different Model to Partial View

Did a quick search and couldn't find this information anywhere online, so here goes.

Here's my scenario.

I Create new MVC project. (I'm using v4, but it would apply in earlier as well), and choose Internet Application. AccountModels.cs is created in my models folder.

There are 2 classes I'm concerned about. UserProfile and RegisterModel.

My scenario involves saving reuse and creating a partialview for creating and editing the user information. A fairly common scenario in web development. So I create the partialview, and use the Model Declaration of UserProfile. I include all information inside of this that will be reused among the 2 views. In my situation, the password and confirm password are the fields I'm not re-using, so those won't be included in my partialview.

So my views look like:

_UserInfo (Partial View):

@model UserProfile

    @Html.LabelFor(m => m.UserName)
    @Html.TextBoxFor(m => m.UserName)


RegisterPage:

...
Registration Form
       


               @Html.Partial("_UserInfo", Model)

                    @Html.LabelFor(m => m.Password)
                    @Html.PasswordFor(m => m.Password)
               
    ...

    But wait!  This generates an error msg stating that the model type is not the same.  How do I pass a valid model type in so that my controller can still read the data back?

    At the top of the RegistePage, I add the following:

    @model RegisterModel
    @{
        ViewBag.Title = "Register";
        UserProfile user = new UserProfile();
    }

    and change my RegisterPage to pass in user instead of Model, such as:

    @Html.Partial("_UserInfo", user)

    That's it!  Now I can reuse this in an edit profile page and simply use UserProfile as my model type, and pass it into the partialview like:

    @Html.Partial("_UserInfo", Model)

    and the partialview will render it with no problems.