Click here to Skip to main content
15,860,859 members
Articles / Programming Languages / C#

HTML5, jQuery Mobile and ASP.NET MVC 4 – Using the ViewModel between the model and controller

Rate me:
Please Sign up or sign in to vote.
4.79/5 (16 votes)
30 Oct 2013CPOL5 min read 104.1K   40   19
Using the ViewModel between the model and controller.

To get started with the development, we have seen the post Introduction to HTML5 Development Using VS 2010, HTML5, jQuery Mobile and ASP.NET MVC 4.

See http://bit.ly/HTML5JQuery for more information

In an enterprise application development scenario, we might need to aggregate some of the models/data sources and present it as a whole to the controller. For simplicity, let us take a case where we need to enter a new student Name, Grade, and the State as shown in Fig 1.

The Grades are A, B, and C. But it might make much sense if we can show these grades as First Class, Second Class, Third Class instead of A,B, and C in the UI. So in the UI, we need to show First Class, Second Class, Third Class but while saving the data we need to save the corresponding values in the DB. Same holds for the state as well. When the user clicks on state dropdown selection icon, the states list pops up and displays all the states. When a state is selected, it is shown in the UI but when saved to the DB, the code names are saved like CA for California, as shown in figure 2.

image

Fig 1: Form for entering new student information

image

Fig 2: When clicked on the State drop down list, the above screen pops up.

The Magic of ViewModel: ViewModels allow you to shape multiple entities from one or more data models or sources into a single object, optimized for consumption and rendering by the view. The below figure 3 illustrates the concept of a ViewModel:

image

Fig 3: StudentViewModel aggregating the different models and data sources and supplying the information to the view as a single entity.

The purpose of a ViewModel is for the view to have a single object to render, alleviating the need for UI logic code in the view that would otherwise be necessary. This means the only responsibility, or concern, of the view is to render that single ViewModel object, aiding in a cleaner separation of concerns (SoC). Concerns are distinct aspects of the application that have a particular purpose (i.e., concern), and keeping these aspects apart means your application is more organized, and the code more focused. Putting data manipulation code in its own location away from the view and controller, enforces SoC. Using ViewModels in MVC leads to more easily maintainable and testable code.

Let us create our data sources. The first one is the grade and the code is as follows. The Grades class is a simple Dictionary object containing two type parameters of type string. The class also contains the definitions for all the members in the Dictionary (i.e., the grades data). The only property in the Grades class is the GradeSelectList, which is an object that HTML Helpers use with to render an HTML <select> element that displays a listing of grades. The type Dictionary<string, string> in the GradeSelectList property maps to the grades abbreviation then grade name, respectively.

C#
public class Grades
{
    public static SelectList GradeSelectList
    {
        get 
        { 
            return new SelectList(GradeDictionary, "Value", "Key"); 
        }

    }
    public static readonly IDictionary<string, string>
            GradeDictionary = new Dictionary<string, string>
            { 
              {"Choose…",""}
            , { "First Class", "A" }
            , { "Second Class", "B" }
            , { "Third Class", "c" }
            }; 
}

The same login for the states. The code for StatesDictionary is as follows:

C#
public class StatesDictionary
{
    public static SelectList StateSelectList
    {
        get { return new SelectList(StateDictionary, "Value", "Key"); }
    }

    public static readonly IDictionary<string, string>
        StateDictionary = new Dictionary<string, string> { 
      {"Choose…",""}
    , { "Alabama", "AL" }
    , { "Alaska", "AK" }
    , { "Arizona", "AZ" }
    , { "Arkansas", "AR" }
    , { "California", "CA" }
    , { "Colorado", "CO" }
    , { "Connecticut", "CT" }
    , { "Delaware", "DE" }
    , { "District of Columbia", "DC" }
    , { "Florida", "FL" }
    , { "Georgia", "GA" }
    , { "Hawaii", "HI" }
    , { "Idaho", "ID" }
    , { "Illinois", "IL" }
    , { "Indiana", "IN" }
    , { "Iowa", "IA" }
    , { "Kansas", "KS" }
    , { "Kentucky", "KY" }
    , { "Louisiana", "LA" }
    , { "Maine", "ME" }
    , { "Maryland", "MD" }
    , { "Massachusetts", "MA" }
    , { "Michigan", "MI" }
    , { "Minnesota", "MN" }
    , { "Mississippi", "MS" }
    , { "Missouri", "MO" }
    , { "Montana", "MT" }
    , { "Nebraska", "NE" }
    , { "Nevada", "NV" }
    , { "New Hampshire", "NH" }
    , { "New Jersey", "NJ" }
    , { "New Mexico", "NM" }
    , { "New York", "NY" }
    , { "North Carolina", "NC" }
    , { "North Dakota", "ND" }
    , { "Ohio", "OH" }
    , { "Oklahoma", "OK" }
    , { "Oregon", "OR" }
    , { "Pennsylvania", "PA" }
    , { "Rhode Island", "RI" }
    , { "South Carolina", "SC" }
    , { "South Dakota", "SD" }
    , { "Tennessee", "TN" }
    , { "Texas", "TX" }
    , { "Utah", "UT" }
    , { "Vermont", "VT" }
    , { "Virginia", "VA" }
    , { "Washington", "WA" }
    , { "West Virginia", "WV" }
    , { "Wisconsin", "WI" }
    , { "Wyoming", "WY" }    
    // more states 
    };
}

Data that lives in small lists and infrequently changes, like the Grades, StatesDictionary class, exists in all types of applications.

Creating the Model

Now we need a model that collects the student’s name, the grade, and the state he is from as shown in Figure 1. The StudentModels class definition captures these features in simple data structure. Let us now create a StudentModels class as shown below. Create a file StudentModels.cs under the Models folder and add the following code:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace TagStatus.Models
{
    public class StudentModels
    {
        [Display(Name = "Student Name here")]
        [Required()]
        public string StudentName { get; set; }
        public string Grade { get; set; }
        public string State { get; set; }
    }
}

Creating the ViewModel

Because of the data coming from different sources that needs to be displayed in the view, coding and maintenance will be easier if you use a ViewModel. ViewModels are a combination of one or more types that together shape data that goes to the view for consumption and rendering. A ViewModel is just a class. To get started, create a new folder named ViewModels and add a new code file StudentViewModel.cs to it. To create the StudentViewModel ViewModel, add the StudentModels, Grades, and StatesDictionary types as properties to form one StudentViewModel class. In the source code below, the StudentViewModel class contains the newly defined properties.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using TagStatus.Models;
namespace TagStatus.ViewModels
{
    public class StudentViewModel
    {
        public StudentModels Student { get; set; }
        public Grades Grades { get; set; }
        public StatesDictionary States { get; set; }
        public StudentViewModel(StudentModels student)
        {
            Student = student;
            Grades = new Grades();
            States = new StatesDictionary();
        }
        public StudentViewModel()
        {
            Student = new StudentModels(); ;
            Grades = new Grades();
            States = new StatesDictionary();
        }
    }
}

Creating the Controller

After creating the ViewModel, the next steps are to instantiate it in a controller and return it to the view. I am doing R & D on this new MVC4 and so you will see some messy code.

The following code creates a Controller Passing the ViewModel to the View and the code of interest for us is public ActionResult StudentInfo() and this gets executed while the application is firing up.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using TagStatus.Models;
using TagStatus.ViewModels;
namespace TagStatus.Controllers
{
    public class StudentController : Controller
    {
        //public string StudentName { get; set; }
        //public int Grade { get; set; }
        //
        // GET: /Student/
        public ActionResult Index()
        {
            StudentModels stdm = new StudentModels();
            StudentViewModel stdvm = new StudentViewModel(stdm);
            return View(stdvm);
        }
        //[AllowAnonymous]
        //public ActionResult StudentInfo()
        //{
        //    return View();
        //}
        [AllowAnonymous]
        [HttpPost]
        public ActionResult StudentInfo(StudentModels model)
        {
            if (ModelState.IsValid)
            {
                model.StudentName = model.State;
            }
            return View(model);
        }
        [AllowAnonymous]
        public ActionResult StudentInfo()
        {
            StudentViewModel model = new StudentViewModel();
                //model.StudentName = model.State;
            return View(model);
        }
    }
}

Creating HTML5 Mobile Forms in ASP.NET MVC 4 Views:

In Visual Studio 2010, Right click on project and Add New Item command to create StudentInfo.cshtml, the view that will host your HTML5 form. Inside the view, various ASP.NET MVC 4 Html Helpers present components of the StudentViewModel by rendering HTML elements that best fit the data types they map to in the ViewModel. For example, Grade renders as an HTML drop-down list so that the user can easily select an item rather than manually enter it.

The code for StudentInfo.cshtml is as follows.

XML
@model TagStatus.ViewModels.StudentViewModel
@{
    ViewBag.Title = "Student Info";
}

<h2> New Student </h2>
@using (Html.BeginForm("Results","Home"))
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Enter Student Information!</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.Student.StudentName)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(Model => Model.Student.StudentName)
           @Html.ValidationMessageFor(Model => Model.Student.StudentName)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Student.Grade)
        </div>
        <div class="editor-field">
            @Html.DropDownListFor(Model => Model.Student.Grade, Grades.GradeSelectList)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Student.State)
        </div>
        <div class="editor-field">
            @Html.DropDownListFor(Model => Model.Student.State, StatesDictionary.StateSelectList)
        </div>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

Download the source code from here and make the following change in the Global.asax file.

XML
routes.MapRoute(
 
name: "Default",
 
url: "{controller}/{action}/{id}",
 
//defaults: new { controller = "Tag", action = "Lookup", id = UrlParameter.Optional }
 
defaults: new { controller = "Student", action = "StudentInfo", id = UrlParameter.Optional }
 
//defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
 
);

If you don’t go after what you want, you’ll never have it. If you don’t ask, the answer is always no. If you don’t step forward, you’re always in the same place. – Nora Roberts

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO Astrani Technology Solutions
United States United States
Kishore Babu Gaddam is a Senior Technology Consultant, Technology Evangelist turned Technology Entrepreneur and a regular speaker at national conferences, regional code camps and local user groups with over 14 years of experience in software product development. His experience includes building & managing award-winning software development teams, managing customer relationships, marketing and launching new software products & services. Kishore launched his technology career almost 15 years ago with a Robotics software development startup and has served in multiple roles since including developer, innovation leader, consultant, technology executive and business owner.

A technology specialist in C++, C#, XAML and Azure, he successfully published two applications to Windows store http://bit.ly/WinStoreApp and http://bit.ly/FlagsApp.

Kishore is the author of the popular Microsoft Technologies blog at http://www.kishore1021.wordpress.com/ and his work on Portable Class Library project in Visual Studio 2012– .NET 4.5 was featured on Channel 9 at http://bit.ly/msdnchannel9. Kishore enjoys helping people understand technical concepts that may initially seem complex and perform lot of Research & Development on emerging technologies to help solve some of the toughest customer issues. Kishore spends a lot of time teaching and mentoring developers to learn new technologies and to be better developers. He is a speaker at various code camps around Washington DC area, mainly at Microsoft Technology Center for NOVA code camp (http://bit.ly/novacc12), CMAP Code Camp Fall 2012 (http://bit.ly/novacc12), etc. The majority of his software development experience has centered on Microsoft technologies including MFC, COM, COM+, WCF, WPF, winRT, HTML5, RestAPI and SQL Server. You can follow Kishore on Twitter at www.twitter.com/kishore1021. He can be reached on email at researcherkishore@outlook.com

Comments and Discussions

 
SuggestionRe: Missing Source Code ? Pin
s_wong2-Nov-12 5:50
s_wong2-Nov-12 5:50 
GeneralMy vote of 4 Pin
pradiprenushe1-Aug-12 23:27
professionalpradiprenushe1-Aug-12 23:27 
GeneralRe: My vote of 4 Pin
kishore Gaddam14-Feb-14 3:37
kishore Gaddam14-Feb-14 3:37 
GeneralMy vote of 2 Pin
JoeCane25-Jul-12 6:43
JoeCane25-Jul-12 6:43 
GeneralRe: My vote of 2 Pin
kishore Gaddam20-Aug-12 8:34
kishore Gaddam20-Aug-12 8:34 
The source code is provided in the article as a link at
Download the source code from here https://skydrive.live.com/redir.aspx?cid=38ecce05b21b8b44&resid=38ECCE05B21B8B44!590&parid=38ECCE05B21B8B44!589[^] and make the following change in the Global.asax file.

routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
//defaults: new { controller = "Tag", action = "Lookup", id = UrlParameter.Optional }
defaults: new { controller = "Student", action = "StudentInfo", id = UrlParameter.Optional }
//defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Never be afraid to try something new. Remember, amateurs built the ark; Professionals built the Titanic.

QuestionFormatting! Pin
Vivek Krishnamurthy1-Jul-12 22:52
Vivek Krishnamurthy1-Jul-12 22:52 
AnswerRe: Formatting! Pin
kishore Gaddam3-Jul-12 3:25
kishore Gaddam3-Jul-12 3:25 
SuggestionPlease check! Pin
ThatsAlok1-Jul-12 20:23
ThatsAlok1-Jul-12 20:23 
GeneralRe: Please check! Pin
kishore Gaddam3-Jul-12 3:20
kishore Gaddam3-Jul-12 3:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.