jQuery 1.4 New Features you Must Know

jQuery 1.4 was recently released. This wasn't simply a maintenance release as some had speculated; there are many new features, enhancements and performance improvements included in 1.4! This post covers the new features and enhancements that you may find beneficial.
You can download jQuery 1.4 right now, here: http://code.jquery.com/jquery-1.4.js

Pre 1.4, jQuery supported adding attributes to an element collection via the useful "attr" method, which can be passed both an attribute name and value, or an object specifying several attributes. jQuery 1.4 adds support for passing an attributes object as the second argument to the jQuery function itself, upon element creation.
Let's say you need to create an anchor element with several attributes. With 1.4 it's as simple as:
1
2
3
4
5
6
7
jQuery('<a/>', {
    id: 'foo',
    href: 'http://google.com',
    title: 'Become a Googler',
    rel: 'external',
    text: 'Go to Google!'
});
You may have noticed the "text" attribute— you'll probably be wondering what that's doing there, after all there's no "text" attribute for anchors! Well, jQuery 1.4 utilises its very own methods when you pass certain attributes. So the "text" attribute specified above would cause jQuery to call the ".text()" method, passing "Go to Google!" as its only argument.
A better example of this in action:
01
02
03
04
05
06
07
08
09
10
jQuery('<div/>', {
    id: 'foo',
    css: {
        fontWeight: 700,
        color: 'green'
    },
    click: function(){
        alert('Foo has been clicked!');
    }
});
The "id" is added as a regular attribute, but the "css" and "click" properties trigger calling of each respective method. The above code, before the 1.4 release, would have been written like this:
1
2
3
4
5
6
7
8
9
jQuery('<div/>')
    .attr('id', 'foo')
    .css({
        fontWeight: 700,
        color: 'green'
    })
    .click(function(){
        alert('Foo has been clicked!');
    });

Three new methods have been added to the DOM traversal arsenal in 1.4, "nextUntil", "prevUntil" and "parentsUntil". Each of these methods will traverse the DOM in a certain direction until the passed selector is satisfied. So, let's say you have a list of fruit:
1
2
3
4
5
6
7
8
9
<ul>
    <li>Apple</li>
    <li>Banana</li>
    <li>Grape</li>
 
    <li>Strawberry</li>
    <li>Pear</li>
    <li>Peach</li>
</ul>
You want to select all of items after "Apple", but you want to stop once you reach "Strawberry". It couldn't be simpler:
1
2
jQuery('ul li:contains(Apple)').nextUntil(':contains(Pear)');
// Selects Banana, Grape, Strawberry

Instead of chaining a bunch of event binding methods together, you can lump them all into the same call, like so:
01
02
03
04
05
06
07
08
09
10
11
jQuery('#foo).bind({
    click: function() {
        // do something
    },
    mouseover: function() {
        // do something
    },
    mouseout: function() {
        // do something
    }
})
This also works with ".one()".

Instead of just defining one easing function for a single animation, you can now define a different easing function for each property that you're animating. jQuery includes two easing functions, swing (the default) and linear. For other ones you'll need to download them separately!
To specify an easing function for each property simply define the property as an array, with the first value being what you want to animate that property to, and the second being the easing function to use:
1
2
3
4
jQuery('#foo').animate({
    left: 500,
    top: [500, 'easeOutBounce']
}, 2000);

You can also define per-property easing functions in the optional options object as property name-value pairs in the "specialEasing" object:
1
2
3
4
5
6
7
8
9
jQuery('#foo').animate({
    left: 500,
    top: 500
}, {
    duration: 2000,
    specialEasing: {
        top: 'easeOutBounce'
    }
});
Editor's Note - The author of this article, James Padolsey, is being modest. This new feature was his idea!

jQuery 1.4 adds support for delegating the "submit", "change", "focus" and "blur" events. In jQuery, we use the ".live()" method to delegate events. This is useful when you have to register event handlers on many elements, and when new elements may be added over time (using ".live()" is less-costly than re-binding continually).
But, be careful! You must use the event names, "focusin" and "focusout" if you want to delegate the "focus" and "blur" events!
1
2
3
jQuery('input').live('focusin', function(){
    // do something with this
});
jQuery 1.4 provides a new "proxy" function under the jQuery namespace. This function takes two arguments, either a "scope" and a method name, or a function and the intended scope. JavaScript's "this" keyword can be quite tricky to keep a hold of. Sometimes you won't want it to be an element, but instead an object that you've previously created.
For example, here we've got an "app" object which has two properties, a "clickHandler" method and a config object:
1
2
3
4
5
6
7
8
var app = {
    config: {
        clickMessage: 'Hi!'
    },
    clickHandler: function() {
        alert(this.config.clickMessage);
    }
};
The "clickHandler" method, when called like "app.clickHandler()" will have "app" as its context, meaning that the "this" keyword will allow it access to "app". This works quite well if we simply call:
1
app.clickHandler(); // "Hi!" is alerted
Let's try binding it as an event handler:
1
jQuery('a').bind('click', app.clickHandler);
When we click an anchor it doesn't appear to work (nothing is alerted). That's because jQuery (and most sane event models) will, by default, set the context of the handler as the target element,- that is, the element that's just been clicked will be accessible via "this". But we don't want that, we want "this" to be set to "app". Achieving this in jQuery 1.4 couldn't be simpler:
1
2
3
4
jQuery('a').bind(
    'click',
    jQuery.proxy(app, 'clickHandler')
);
Now whenever an anchor is clicked, "Hi!" will be alerted!
The proxy function returns a "wrapped" version of your function, with "this" set to whatever you specify. It's useful in other contexts too, such as passing callbacks to other jQuery methods, or to plugins.

You can now add a delay to your animation queues. In fact, this works on any queue, but its most common use case will probably be with the "fx" queue. This allows you to pause between animations without having to mess with callbacks and calls to "setTimeout". The first argument to ".delay()" is the amount of milliseconds you want to delay for.
1
2
3
4
jQuery('#foo')
    .slideDown() // Slide down
    .delay(200) // Do nothing for 200 ms
    .fadeIn(); // Fade in
If you want to delay a queue other than the default "fx" queue, then you'll need to pass the queue name as the second argument to ".delay()".

jQuery 1.4 makes it easy to check if an element (or collection) ".has()" something. This is the programmatic equivalent to jQuery's selector filter, ":has()". This method will select all elements in the current collection that contain at least one element that complies with the passed selector.
1
jQuery('div').has('ul');
That would select all DIV elements that contain UL elements. In this situation you'd probably just use the selector filter (":has()"), but this method is still useful when you need to filter a collection programmatically.
jQuery 1.4 also reveals the "contains" function under the jQuery namespace. This is a low-level function that accepts two DOM nodes. It'll return a boolean indicating whether the second element is contained within the first element. E.g.
1
2
jQuery.contains(document.documentElement, document.body);
// Returns true - <body> is within <html>

We've had the ".wrap()" method for a while now. jQuery 1.4 adds the ".unwrap()" method which does the complete opposite. If we assume the following DOM structure:
1
2
3
<div>
    <p>Foo</p>
</div>
We can unwrap the paragraph element like so:
1
jQuery('p').unwrap();
The resulting DOM structure would be:
1
<p>Foo</p>
Essentially, this method simply removes the parent of any element.

The new ".detach()" method allows you to remove elements from the DOM, much like the ".remove()" method. The key difference with this new method is that it doesn't destroy the data held by jQuery on that element. This includes data added via ".data()" and any event handlers added via jQuery's event system.
This can be useful when you need to remove an element from the DOM, but you know you'll need to add it back at a later stage. Its event handlers and any other data will persist.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
var foo = jQuery('#foo');
 
// Bind an important event handler
foo.click(function(){
    alert('Foo!');
});
 
foo.detach(); // Remove it from the DOM
 
// … do stuff
 
foo.appendTo('body'); // Add it back to the DOM
 
foo.click(); // alerts "Foo!"

jQuery 1.4 gives you two new ways to use the ".index()" method. Previously, you could only pass an element as its argument and you'd expect a number to be returned indicating the index of that element within the current collection.
Passing no arguments now returns the index of an element amongst its siblings. So, assuming the following DOM structure:
1
2
3
4
5
6
7
8
9
<ul>
    <li>Apple</li>
    <li>Banana</li>
    <li>Grape</li>
 
    <li>Strawberry</li>
    <li>Pear</li>
    <li>Peach</li>
</ul>
When a list item is clicked you want to find out the index of the clicked element amongst all the other list items. It's as simple as:
1
2
3
jQuery('li').click(function(){
    alert( jQuery(this).index() );
});
jQuery 1.4 also allows you to specify a selector as the first argument to ".index()", doing so will give you the index of the current element amongst the collection produced from that selector.
You should note that what's returned from this method is an integer, and it will return -1 if the selector/element passed cannot be found in the document.

Most of the DOM manipulation methods now support passing a function as the sole argument (or second, in the case of ".css()" & ".attr()"). This function will be run on every element in the collection to determine what should be used as the real value for that method.
The following methods have this capability:
  • after
  • before
  • append
  • prepend
  • addClass
  • toggleClass
  • removeClass
  • wrap
  • wrapAll
  • wrapInner
  • val
  • text
  • replaceWith
  • css
  • attr
  • html
Within the callback function, you'll have access to the current element in the collection via "this" and its index via the first argument.
1
2
3
jQuery('li').html(function(i){
    return 'Index of this list item: ' + i;
});
Also, with some of the above methods you'll also get a second argument. If you're calling a setter method (like ".html()" or ".attr('href)") you'll have access to the current value. E.g.
1
2
3
jQuery('a').attr('href', function(i, currentHref){
    return currentHref + '?foo=bar';
});
As you can see, with the ".css()" and ".attr()" methods, you would pass the function as the second argument, since the first would be used to name the property you wish to change:
1
2
3
jQuery('li').css('color', function(i, currentCssColor){
    return i % 2 ? 'red' : 'blue';
});
jQuery 1.4 adds two new helper functions (stored directly under the jQuery namespace) that help you determine what type of object you're dealing with.
First, there's "isEmptyObject", this function returns a boolean indicating whether or not the the passed object is empty (devoid of properties - direct and inherited). Second, there's "isPlainObject", which will return a boolean indicating whether the passed object is a plain JavaScript object, that is, one created via "{}" or "new Object()".
1
2
3
4
5
6
jQuery.isEmptyObject({}); // true
jQuery.isEmptyObject({foo:1}); // false
 
jQuery.isPlainObject({}); // true
jQuery.isPlainObject(window); // false
jQuery.isPlainObject(jQuery()); // false
Read more about: isPlainObject(…), isEmptyObject(…)
jQuery's ".closest()" method now accepts an array of selectors. This is useful when you want to traverse the ancestors of an element, looking for (more than one) closest elements with certain characteristics.
In addition, it now accepts a context as the second argument, meaning that you can control just how far or how close you want the DOM traversed to. Both of these enhancements accommodate rare use cases but they are used internally to great effect!
Read more about .closest(…)
As mentioned, to delegate the "focus" and "blur" events you must use these new events, called "focusin" and "focusout". These events allow you to take action when an element, or a descendant of an element, gains focus.
1
2
3
4
5
6
7
jQuery('form')
    .focusin(function(){
        jQuery(this).addClass('focused');
    });
    .focusout(function(){
        jQuery(this).removeClass('focused');
    });

You should also note that both of these events do not propagate ("bubble"); they are captured. This means that the outermost (ancestor) element will be triggered before the causal "target" element. 

Multiple Models in a View in MVC

Introduction

When I was a beginner for ASP.NET MVC, I faced a question many times: how many ways do you know to use/pass multiple models in/to a view? At that time, I knew only two ways, then I learned some other ways to achieve the same. In this article, I will share my learning so far. Hope it will be helpful for others.
Pre-requisite: you should be at intermediate level with C# and ASP.NET MVC. If you are absolute new to C# and ASP.NET MVC, please look for other resources to understand terms used here. You can put comment below article in case you need any detail. I will be happy to help. Thanks.
There are many ways of using multiple models in a view, most frequently used are given below:
  • ViewData
  • ViewBag
  • PartialView
  • TempData
  • ViewModel
  • Tuple
All the above ways of using multiple models in view have their place but we need to think and pick which one fits our requirements. All techniques have their own advantages and disadvantages.
To understand the article better, please download the attached code, have an overview of the code, then follow the steps given in this article.

Overview of Sample Demo

The attached code solution has six views demonstrating the following:
  • How to pass multiple models using ViewData
  • How to pass multiple models using ViewBag
  • How to pass multiple models using PartialView
  • How to pass multiple models using TempData
  • How to pass multiple models using ViewModel
  • How to pass multiple models using Tuple
In the sample demo, all views will have similar HTML structure to get same layout but implementation to pass models to the view will be different.
Structure of the HTML tags is shown below only code inside the scripts tag will be changed as per the scenarios.
HTML Layout of Views
Output of all demos will be similar to the screenshot shown below:
HTML Layout of Views

Creating Basic Structure of Sample Demo

Let's get started by creating a sample demo application. Follow the below steps:
  1. Open Visual Studio 2012, select ASP.NET MVC4 Web Application template and give it project name as MultipleModelDemo and click OK. If you are using Visual Studio 2013 and MVC 5, Please look into the Update for VS 2013 / MVC 5 section below. Choose Application Template for ASP.NET MVC4
  2. Select a template as Basic application then click OK. Visual Studio adds a MultipleModelDemo project in solution as shown below in screenshot. Choose Application Template for ASP.NET MVC4
  3. Right click on the Models folder, add a Models.cs file. Now we need to add three models named as Course, Faculty and Student by writing the following code as shown below:
    public class Course
    {
        public int CourseId { get; set; }
        public string CourseName { get; set; }
    }
    
    public class Faculty
    {
        public int FacultyId { get; set; }
        public string FacultyName { get; set; }
        public List<Course> AllotedCourses { get; set; }
    }
    
    public class Student
    {
        public int EnrollmentNo { get; set; }
        public string StudentName { get; set; }
        public List<Course> EnrolledCourses { get; set; }
    }
  4. Add a class file under the Models folder named as Repository.cs file, which will have the implementation of methods to get hardcoded data for application in order to keep it convenient. Following is the code for GetCourse method which will return a list of courses:
    public List<Course> GetCourses()
    {
        return new List<Course> { 
            new Course () {  CourseId = 1, CourseName = "Chemistry"}, 
            new Course () {  CourseId = 2, CourseName = "Physics"},
            new Course () {  CourseId = 3, CourseName = "Math" },
            new Course () {  CourseId = 4, CourseName = "Computer Science" }
        };
    }           
    Following is the code GetFaculties method which will return a list of faculties:
    public List<Faculty> GetFaculties()
    {
        return new List<Faculty> {                 
            new Faculty () {  FacultyId = 1, FacultyName= "Prakash",
                AllotedCourses = new List<Course> 
                {new Course () { CourseId = 1, CourseName = "Chemistry"},
                                 new Course () { CourseId = 2, CourseName = "Physics"},
                                 new Course () { CourseId = 3, CourseName = "Math"},
            }}, 
            new Faculty () {  FacultyId = 2, FacultyName= "Ponty" ,
                AllotedCourses = new List<Course> 
                {new Course () { CourseId = 2, CourseName = "Physics"},
                                 new Course () { CourseId = 4, CourseName = "Computer Science"}
            }},
            new Faculty () {  FacultyId = 3, FacultyName= "Methu", 
                AllotedCourses = new List<Course> 
                {new Course () { CourseId = 3, CourseName = "Math"},
                                 new Course () { CourseId = 4, CourseName = "Computer Science"}
            }}
        };
    }           
    Following is the code for GetStudents method which will return a list of students:
    public List<Student> GetStudents()
    {
        List<Student> result = new List<Student> { 
            new Student () { EnrollmentNo = 1, StudentName= "Jim", 
                EnrolledCourses = new List<Course> 
                { new Course () { CourseId = 1, CourseName = "Chemistry"},
                                  new Course () { CourseId = 2, CourseName = "Physics"},
                                  new Course () { CourseId = 4, CourseName = "Computer Science"}
            }},
            
            new Student () {  EnrollmentNo = 2, StudentName= "Joli",
                EnrolledCourses = new List<Course> 
                { new Course () { CourseId = 2, CourseName = "Physics"} ,
                                  new Course () 
                                  { CourseId = 4, CourseName = "Computer Science"}
            }},
            
            new Student () {  EnrollmentNo = 3, StudentName= "Mortin",
                EnrolledCourses = new List<Course>
                {  new Course () { CourseId = 3, CourseName = "Math"},
                                   new Course () { CourseId = 4, CourseName = "Computer Science"}
            }}
        };
        
        return result;
    }           
  5. Add a HomeController to Controller folder. We will write the code in HomeController later.
  6. In Shared folder, we will modify the existing code in _Layout.cshtml file. First write the following code in head tag:
             <head>
                <meta charset="utf-8" />
                <meta name="viewport" content="width=device-width" />           
    
               @*Referenced  js and css files which comes with template*@
                <script src="~/Scripts/jquery-1.8.2.min.js"></script>
                <link href="~/Content/Site.css" rel="stylesheet" />
    
                @*Referenced appcss file having custom CSS*@
                <link href="~/Content/appcss/appcss.css" rel="stylesheet" />    
            </head>           
    Write the following code in body tag:
    <body>
        @* Define the place for navigation links in left side of the page*@
        <div class="navigationPanel">
            <div style="margin: 40px 25px 2px 25px;">
                <h3>Links to Demostrations</h3>
                <a href="~/Home/ViewDataDemo">ViewData Demo</a>
                <br />
                <br />
                <a href="~/Home/ViewBagDemo">ViewBag Demo</a>
                <br />
                <br />
                <a href="~/Home/PartialViewDemo">PartialView Demo</a>
                <br />
                <br />
                <a href="~/Home/TempDataDemo">TempData Demo</a>
                <br />
                <br />
                <a href="~/Home/ViewModelDemo">ViewModel Demo</a>
                <br />
                <br />
                <a href="~/Home/TupleDemo">Tuple Demo</a>
            </div>
        </div>
        <div style="float: left; margin: 25px 2px 2px 80px;">
            @RenderBody()
        </div>
    </body>
    So far, we have created basic code which we will be using in all scenarios. Further, we will learn each scenario one by one.

Passing Multiple Models using ViewData

ViewData is used to pass data from a controller to a view. ViewData is a dictionary of objects that is a type of ViewDataDictionary class. ViewData is defined as property in ControllerBase class. Values stored in ViewData require typecasting to their datatype in view. The values in ViewData are accessible using a key.
  1. First, create a object of Repository class in HomeController.
    Repository _repository = new Repository();             
    Add the following code in HomeController.
    public ActionResult ViewDataDemo()
    {
        ViewData["Courses"] = _repository.GetCourses();
        ViewData["Students"] = _repository.GetStudents();
        ViewData["Faculties"] = _repository.GetFaculties();
        return View();
    }           
    Here ViewDataDemo action method will be passing all three models to its view using ViewData.
  2. Add a view named as ViewDataDemo and write the same code as written below in body tag.
    <body style="background-color: #DBDBB7">
     <h3>Passing Multiple Models using <span class="
     specialText">  <i>ViewData </i> </span> </h3>
     <table>
         <tr>
             <td class="sltCourseText">
                 <h3>Select a Course  </h3>
             </td>
             <td>
                 <select id="sltCourse" class="sltStyle">
                    <option>Select Course </option>
                    @*Iterating Course model using ViewData string as a key *@
                    @foreach (var item in ViewData["Courses"] 
                    as List <MultipleModelDemo.Models.Course>)
                    {         
                         <option>@item.CourseName
                         </option>            
                    }
                 </select>
             </td>
         </tr>
     </table>
         
     <div id="facultyDetailSection">
         <h4>Faculties who teach selected course </h4>
         <div id="facultyDetailTable"> </div>
     </div>
         
     <div id="studentDetailSection">
         <h4>Students who learn selected course </h4>
         <div id="studentDetailTable"> </div>
     </div>
     </body>        
    Here we are iterating Course model using ViewData and casting it into a List<Course>.
  3. Inside the body tag, add a script tag and write the following code. Here we would show the table only when user will select a valid course otherwise the facultyDetailSection and studentDetailSection should not be appearing. We are using fadeout and fadeIn function of jQuery for that purpose.
     <script>
            $(document).ready(function(){
                $("#facultyDetailSection").fadeOut(0);
                $("#studentDetailSection").fadeOut(0);
            });
            
            var selectedCourseName;
            
            $("#sltCourse").change(function () {           
                selectedCourseName = $("#sltCourse").val().trim();
                
                if (selectedCourseName === "Select Course") {
                    $("#facultyDetailSection").fadeOut();
                    $("#studentDetailSection").fadeOut();
                }
                else {
                    getFacultyTable();
                    getStudentTable();
                    $("#facultyDetailSection").fadeIn();
                    $("#studentDetailSection").fadeIn();
                }
            });
     </script>            
    Here on the change event of Course dropdown, we will read the value and confirm if there is a valid selection to display faculties and students. In case of a valid selection, getFacultyTable and getStudentTable function will be executed. Add the following functions in script tag:
        //Create table to display faculty detail
        function getFacultyTable() {         
        $("#facultyDetailTable").empty();
        $("#facultyDetailTable").append("<table id='tblfaculty'  
        class='tableStyle'><tr><th class='tableHeader' style='width:60px;'>
                                            Employee ID </th> 
                                            <th class='tableHeader'>Faculty Name 
                                            </th> </tr> </table>");
    
        //Get all faculties with the help of model 
        //(ViewData["Faculties"]), and convert data into json format. 
        var allFaculties = @Html.Raw(Json.Encode(ViewData["Faculties"]));
    
        for (var i = 0; i  < allFaculties.length; i++) {
            var allotedCourses = allFaculties[i].AllotedCourses;
            for (var j = 0; j  < allotedCourses.length; j++) {
                if(allotedCourses[j].CourseName === selectedCourseName)
                    $("#tblfaculty").append
                    (" <tr> <td class='tableCell'>"  + 
                    allFaculties[i].FacultyId 
                        + " </td> <td class='tableCell'>"+
                        allFaculties[i].FacultyName+" </td> </tr>");
            }
        }
    }
    
    //Create table to display student detail
    function getStudentTable() {
        $("#studentDetailTable").empty();
        $("#studentDetailTable").append(" <table id='tblStudent' 
        class='tableStyle'> <tr> <th class='tableHeader' style='width:60px;'>
                                            Roll No </th> <th 
                                            class='tableHeader'>Student Name 
                                            </th> </tr> </table>");
    
        //Get all students with the help of model 
        //(ViewData["Students"]), and convert data into json format. 
        var allStudents = @Html.Raw(Json.Encode(ViewData["Students"]));
    
        for (var i = 0; i  < allStudents.length; i++) {
            var studentCourses = allStudents[i].EnrolledCourses;
            for (var j = 0; j  < studentCourses.length; j++) {
                if(studentCourses[j].CourseName === selectedCourseName)                      
                    $("#tblStudent").append(" <tr> 
                    <td class='tableCell'>"  + allStudents[i].EnrollmentNo 
                        + " </td> <td  class='tableCell'>
                        "+allStudents[i].StudentName+" </td> </tr>");
            }
        }           
    }            
Note: As we have mentioned, all view will have same layout so further demos will have almost the same code as you have written in body tag of ViewDataDemo.cshtml file, now in further demos we just need to modify foreach function to fill data in dropdown and two lines of code in getFacultyTable and getStudentTable JavaScript function.

Passing Multiple Models using ViewBag

ViewBag is also used to pass data from a controller to a view. It is a dynamic property which comes in ControllerBase class that is why it doesn’t require typecasting for datatype.
  1. Add the following code in HomeController:
    public ActionResult ViewBagDemo()
    {
        ViewBag.Courses = _repository.GetCourses();
        ViewBag.Students = _repository.GetStudents();
        ViewBag.Faculties = _repository.GetFaculties();
        return View();
    }            
    Here ViewBagDemo action method will be passing data to view (ViewBagDemo.cshtml) file using ViewBag.
  2. Add a view named as ViewBagDemo. All code will be same as you have written in ViewDataDemo.cshtml file. Just modify input model to foreach function.
    @*Iterating Course model using ViewBag *@
    @foreach (var item in ViewBag.Courses)
    {         
        <option>@item.CourseName</option>            
    }            
  3. In script tag, replace the following line of code in getFacultyTable function:
    //Get all faculties with the help of model 
    // (ViewBag.Faculties), and convert data into json format.                
    var allFaculties = @Html.Raw(Json.Encode(ViewBag.Faculties));
  4. Replace the following line of code in getStudentTable function:
    //Get all students with the help of model(ViewBag.Students), 
    //and convert data into json format.
    var allStudents = @Html.Raw(Json.Encode(ViewBag.Students));

Passing Multiple Models using PartialView

Partial view is used where you need to share the same code (Razor and HTML code) in more than one view. For more details about PartialView, please visit here.
  1. In Home controller, add the following code, PartialViewDemo action method will return a view having the list of all courses only. This action method will not have or pass any faculty or student information as of now.
    public ActionResult PartialViewDemo()
    {
        List<Course> allCourse = _repository.GetCourses();
        return View(allCourse);
    }            
  2. Add a view named as PartialViewDemo. All HTML code will be same as you have written before. Just modify foreach function.
    @*Iterating Course Model*@
    @foreach(var item in Model)
    {         
        <option>@item.CourseName
        </option>            
    }            
  3. In script tag, modify getFacultyTable function as written below:
    function getFacultyTable() {
      $.ajax({
             // Get Faculty PartialView
             url: "/Home/FacultiesToPVDemo",
         type: 'Get',
         data: { courseName: selectedCourseName },
         success: function (data) {
            $("#facultyDetailTable").empty().append(data);
         },
         error: function () {
            alert("something seems wrong");
     }
      });
    }
  4. Modify getStudentTable function as written below:
        function getStudentTable() {
        $.ajax({
            // Get Student PartialView
            url: "/Home/StudentsToPVDemo",
            type: 'Get',
            data: { courseName: selectedCourseName },
            success: function (data) {
                $("#studentDetailTable").empty().append(data);
            },
            error: function () {
                alert("something seems wrong");
            }
        });
    }        
  5. Add a new Action method in HomeController as StudentsToPVDemo and add the following code in StudentsToPVDemo action method.
    public ActionResult StudentsToPVDemo(string courseName)
    {
        IEnumerable <Course> allCourses = _repository.GetCourses();
        var selectedCourseId = (from c in allCourses where 
        c.CourseName == courseName select c.CourseId).FirstOrDefault();
        
        IEnumerable <Student> allStudents = _repository.GetStudents();
        var studentsInCourse = allStudents.Where(s => 
        s.EnrolledCourses.Any(c => c.CourseId == selectedCourseId)).ToList();
        
        return PartialView("StudentPV", studentsInCourse); 
    }
  6. Add a PartialView to the Shared folder by right clicking on StudentsToPVDemo action method, give it name as StudentPV. StudentsToPVDemo action will return StudentPV PartialView having the list of students studying in a particular course.
  7. Add the following code in StudentPV.cshtml file.
    @model  IEnumerable <MultipleModelDemo.Models.Student>
     <table id="tblFacultyDetail" class="tableStyle">
             <tr>
             <th class="tableHeader" style="width:60px;">Roll No </th>
             <th class="tableHeader">Student Name </th>
             </tr>
        @foreach (var item in Model)
        {
              <tr>
                 <td  class="tableCell" >@item.EnrollmentNo </td>
                 <td class="tableCell">@item.StudentName </td>
             </tr>
        }       
     </table>
  8. Add a new action method to call PatialView for faculties in HomeController. Name it as FacultiesToPVDemo and add the following code:
    public ActionResult FacultiesToPVDemo(string courseName)
    {
        IEnumerable <Course> allCourses = _repository.GetCourses();
        var selectedCourseId = (from c in allCourses where 
        c.CourseName == courseName select c.CourseId).FirstOrDefault();
        
        IEnumerable <Faculty> allFaculties = _repository.GetFaculties();
        var facultiesForCourse = allFaculties.Where(f => 
        f.AllotedCourses.Any(c =>  c.CourseId == selectedCourseId)).ToList();
        
        return PartialView("FacultyPV", facultiesForCourse);
      }            
  9. Add a PartialView named as FacultyPV as we did for student PartialView, write the same code as you have written in StudentPV.cshtml file. Just replace one line of code as:
    @model  IEnumerable<MultipleModelDemo.Models.Faculty>
  10. FacultiesToPVDemo action will return FacultyPV PartialView having the list of faculties who teach a particular course.

Passing Multiple Models using TempData

TempData is a dictionary of objects that is a type of TempDataDictionary class. TempData is defined as property in ControllerBase class. Values stored in TempData require typecasting to datatype in view. The values in TempData are accessible using a key. It is similar to ViewData but the difference is that it allow us to send and receive the data from one controller to another controller and from one action to another action. It’s all about possible because it internally uses session variables.
For more information about TempData, please visit here. Here, we will use TempData only to hold (at server side HomeController) and pass (to the TempDataDemo.cshtml) List of Courses.
  1. In home controller, add the following code:
    public ActionResult TempDataDemo()
    {
        // TempData demo uses repository to get List<courses> only one time
        // for subsequent request to get List<courses> it will use TempData
        TempData["Courses"] = _repository.GetCourses();
    
        // This will keep Courses data untill next request is served
        TempData.Keep("Courses");
        return View();
    }
  2. Using TempData, we can pass values from one action to another action. TempData["Courses"] having the list of course. We will access this list in FacultiesToTempDataDemo action as shown below:
    public ActionResult FacultiesToTempDataDemo(string courseName)
    {
        var allCourses = TempData["Courses"] as IEnumerable <Course>;
        
        // Since there are two AJAX call on TempDataPage
        // So we keep to keep Courses data for the next one
        TempData.Keep("Courses");
        var selectedCourseId = (from c in allCourses where 
        c.CourseName == courseName select c.CourseId).FirstOrDefault();
        
        IEnumerable <Faculty> allFaculties = _repository.GetFaculties();
        var facultiesForCourse = allFaculties.Where(f => 
        f.AllotedCourses.Any(c => c.CourseId == selectedCourseId)).ToList();
        
        return PartialView("FacultyPV", facultiesForCourse);
    }
    
    public ActionResult StudentsToTempDataDemo(string courseName)
    {
        var allCourses = TempData["Courses"] as IEnumerable <Course>;
        
        // If there is change in course again...it may cause more AJAX calls
        // So we need to keep Courses data
        TempData.Keep("Courses");
        
         var selectedCourseId = (from c in allCourses where 
         c.CourseName == courseName select c.CourseId).FirstOrDefault();
         
        IEnumerable <Student> allStudents = _repository.GetStudents();
        var studentsInCourse = allStudents.Where(s => 
        s.EnrolledCourses.Any(c => c.CourseId == selectedCourseId)).ToList();
        
        return PartialView("StudentPV", studentsInCourse);
    }            
  3. Add a view by right clicking on TempDataDemo action method. Write the same code as you have written in PartialViewDemo.cshtml. Only one line of code needs to modify as written below:
    @*Iterating Course model using TempData["Courses"] *@
    @foreach (var item in TempData["Courses"] 
     as List <MultipleModelDemo.Models.Course>)
    {         
        <option>@item.CourseName </option>            
    }           
    Modify url in getFacultyTable and getStudentTable function respectively as written below:
    url: "/Home/FacultiesToTempDataDemo",
    url: "/Home/StudentsToTempDataDemo",            
    Both Action methods FacultiesToTempDataDemo and StudentsToTempDataDemo will return the same PartialView which we used for PartialView demo.

Passing Multiple Models using ViewModel

ViewModel is a pattern that allow us to have multiple models as a single class. It contains properties of entities exactly need to be used in a view. ViewModel should not have methods. It should be a collection of properties needed for a view.
  1. We have three models (classes) named as Student, Course and Faculty. All are different models but we need to use all three models in a view. We will create a ViewModel by adding a new folder called ViewModels and add a class file called ViewModelDemoVM.cs and write the following code as shown below:
    public class ViewModelDemoVM
    {        
        public List <Course> allCourses { get; set; }
        public List <Student> allStudents { get; set; }
        public List <Faculty> allFaculties { get; set; }
    }            
    Note: As a good practice when you create any ViewModel, it should have suffix as VM or ViewModel.
  2. In the HomeController, add the following code:
    public ActionResult ViewModelDemo()
    {
        ViewModelDemoVM vm = new ViewModelDemoVM();
        vm.allCourses = _repository.GetCourses();
        vm.allFaculties = _repository.GetFaculties();
        vm.allStudents = _repository.GetStudents();
    
        return View(vm);
    }            
    ViewModelDemo is an action method that will return a view having ViewModelDemoVM which has lists of all Courses, Faculties and Students.
  3. Right click on ViewModelDemo to add a view is called ViewModelDemo. ViewModelDemo.cshtml view will use ViewModelDemoVM as Model as shown below:
    @model MultipleModelDemo.ViewModel.ViewModelDemoVM            
  4. Modify foreach function.
    @*Iterating Course ViewModel *@
    @foreach (var item in Model.allCourses)
        {         
            <option>@item.CourseName</option>            
        }            
  5. Replace the following line of code in getFacultyTable function:
    //Get all faculties with the help of viewmodel
    //(Model.allFaculties), and convert data into json format.
    var allFaculties = @Html.Raw(Json.Encode(Model.allFaculties));
  6. Replace the following line of code in getStudentTable function:
    //Get all students with the help of viewmodel(Model.allStudents), 
    //and convert data into json format.
    var allStudents = @Html.Raw(Json.Encode(Model.allStudents));            

Passing Multiple Models using Tuple

Tuple is a new class introduced in .NET Framework 4.0. It is an ordered sequence, immutable, fixed-size collection of heterogeneous (allows us to group multiple kind of data types) objects.
  1. Add the following code in Home controller.
    public ActionResult TupleDemo()
    {
        var allModels = new Tuple <List <Course>, 
        List <Faculty>,  List <Student>>
        (_repository.GetCourses(), _repository.GetFaculties(),  _repository.GetStudents()) { };
         return View(allModels);
    }            
    Here, we are defining a tuple which is having lists of courses, faculties and students. We are passing this tuple to the View.
  2. Add a View named as TupleDemo. Write code as you have written in ViewModelDemo.cshtml file. Just need to replace few lines of code. Replace model declarations as shown below. Here, we will use the namespace used to avoid long fully qualified class names.
    @using MultipleModelDemo.Models;
    @model Tuple <List <Course>, List <Faculty>, List <Student>>            
  3. Modify foreach function:
    @*Iterating Course model using tuple *@
    @foreach (var item in Model.Item1)
        {         
             <option>@item.CourseName </option>            
        }            
    Here Model.Item1 is mapped to Course model.
  4. Inside the JavaScript function called getFacultyTable replace the following line of code:
    var allFaculties = @Html.Raw(Json.Encode(Model.Item2));            
    Here Model.Item2 is mapped with Faculty model.
  5. Inside the JavaScript function called getStudentTable, replace the following line of code:
    var allStudents = @Html.Raw(Json.Encode(Model.Item3));            
    Here Model.Item3 is mapped with Student model.

Update for VS 2013 / MVC 5

If you would like to use Visual Studio 2013 / MVC 5, Step 1 and 2 as given for MVC 4 would be different, So please follow the steps as given below and then start from steps 3 as given for MVC 4 above.
  1. Open Visual Studio 2013, Click on "New Project" and select ASP.NET Web Application template and give it project name as MultipleModelDemo and click OK. Choose Application Template for ASP.NET MVC 5
  2. Select a template as MVC and make sure that all check box given in lower section of popup are unchecked other than MVC. Before clicking OK, we need to change Authentication (since for this demo we are not using either Authentication or Unit Tests to keep it simple and to the point). Please find screen shots below for the same: Visual Studio 2013-MVC-Tempate

    Changing the Authentication from "Individual User Account" to "No Authentication": VisualStudio2013 - No Authentication.png

    Visual Studio adds a MultipleModelDemo project in solution. Now you can follow the step 3 and further as given for MVC 4.

Conclusion


In this article, we learned how to use multiple models in a view. In the article How to Choose the Best Way to Pass Multiple Models, I have shared my findings about when and where to pick a particular way to use multiple models in a view. Your inputs and queries are most welcome. Thanks.