Showing posts with label HttpPost. Show all posts
Showing posts with label HttpPost. Show all posts

Sunday, September 30, 2012

Multiple Checkboxes in MVC 3, and Post selection to Controller Action

This article aims to explain - how to provide a multiple selection checkboxes in MVC 3 application, and the way to fetch the selection in an HttpPost contrller action.

Scenario:
A UI should have checkbox for each weekday (Mon to Sun), and when user submits the form, an HttpPost action should be able to fetch selected Weekdays by user.

We will create an Editor Template for this.
Please note this example is in C#.Net and Razor view, but you should easily be able to convert it in VB.Net and ASPX page if your application demands.

Step - 1: Create a Model (i.e. Type)

namespace MyMVC.Models
{
    public class WeekDaySelectionModel
    {
        public string WeekdDayName { get; set; }
        public bool Selected { get; set; }
    }
}

Step - 2: Create a collection of weekday names in your HttpGet action calling your view:

using System.Collections.Generic;
using MyMVC.Models;
[HttpGet]
public ActionResult EditEntry()
        {
            List<WeekDaySelectionModel> _weekDaySelection = new List<WeekDaySelectionModel>();
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Mon"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Tue"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Wed"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Thu"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Fri"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Sat"});
            _weekDaySelection.Add(new WeekDaySelectionModel { WeekdDayName = "Sun"});

return View("EditEntry", _weekDaySelection);              
}


Step - 3: Create an Editor Template in "..\Views\Shared\EditorTemplates" folder.

File name: WeekDaySelectionModel.cshtml (Make sure the file name is matching with the type name we created in Step 1).

@model MyMVC.Models.WeekDaySelectionModel
<span>
    @Html.HiddenFor(m => m.WeekdDayName)
    @Html.CheckBoxFor(m => m.Selected)
    @Html.LabelFor(m => m.Selected, Model.WeekdDayName)
</span>

Step - 4: Integrate this editor in your view.

File Name: EditEntry.cshtml

@model System.Collections.Generic.List<MyMVC.Models.WeekDaySelectionModel>
@for (int i = 0; i <= Model.SelectedWeekDays.Count - 1; i++)
{
    @Html.EditorFor(m => m.SelectedWeekDays[i])
}

Step - 5: Catching the selection in HttpPost controller action.

When user submits the pages, an HttpPost controller action will automatically receive the model having "Selected" property updated against each weekday name.

[HttpPost]
        public ActionResult EditEntry(System.Collections.Generic.List<WeekDaySelectionModel> _weekDayNames)
        {
            string selectedWeekDayNames = String.Empty;
            for (int i = 0; i <= _weekDayNames.Count - 1; i++)
            {
                if (_weekDayNames[i].Selected == true)
                {
                    if (String.IsNullOrEmpty(selectedWeekDayNames) == false)
                        selectedWeekDayNames += ",";
                    selectedWeekDayNames += _weekDayNames[i].WeekdDayName;
                }
            }
        }


Wednesday, April 25, 2012

Binding two or more types of objects (models) to single view in ASP.NET MVC

This article aims to explain how we can bind two or more different types of objects to single view in ASP.NET MVC application. (Please note, the code snippets are in razor view engine, but I know its not as such difficult for you to comprehend them in ASPX engine :))

As we know, its straight-forward bind a single type of object (or collection) to a view and we can pass it from Controller action to the View.
I mean, if your need to bind a View to an object of PersonEntity type(or its collection), you can bind, pass, and post it like below:

Binding in View: 
@model MVCTutorialApp.Models.PersonEntity

Passing it from controller action:
public ActionResult PersonEdit()
{
..................
return View("EditPerson", _person);
}

HttpPost action in your controller:

        [HttpPost]

        public ActionResult PersonEdit(PersonEntity  _person)

But sometimes we need to pass multiple different types of objects to a single view.
Say, for example, you have two different types "PersonEntity", and "ContactEntity", and you need to bind them to a single view.

There are various ways to achieve them:
But two of the most ideal approaches are Wrapper class, and System.Tuple

Approach AWrapper class
Create a class that can hold instance of both "PersonEntity" and "ContactEntity".
Like, 
public class PersonContactEntity
    {
        public PersonContactEntity()
        {
        }

        public PersonEntity Person { get; set; }
        public ContactEntity Contact { get; set; }
    }

Now in your corresponding action of controller -
Create an instance of the class "PersonContactEntity".
Assign "Person" and "Contact" properties with the their respective instances.
Pass instance of "PersonContactEntity" to the view. 
public ActionResult PersonContactEdit()
{
PersonContactEntity personContact = new PersonContactEntity();
..................
personContact.Person = person object;
PersonContact.Contact = contact object;
return View("EditPersonContact",  PersonContact );
}


Create your view as strongly typed view by adding following line at top:
@model MVCTutorialApp.Models.PersonContactEntity

Once done, when you write @Model followed by dot (.) the intellisense will show you "Person" and "Contact" both, and you can  now bind your controls, or use them in your view.
Example:

@Html.TextBoxFor(m => m.Person.FullName)
Also, @Model.Contact.Email

And, also corresponding HttpPost method (controller action) can also accept PersonContactEntity when a view post data to controller action:
        [HttpPost]
        public ActionResult PersonEdit(PersonContactEntity   _personContact)

Approach B: System.Tuple
A tuple is a data structure that has a specific number and sequence of elements (Ref: MSDN)
Please visit following MSDN link to know more about tuples

Please note that, Tuple in our scenario should only be used if you do not need to do Post data from View to controller action. As tuple does not have a default constructor, it cannot be used as a parameter in HttpPost method, or you may need to find a workaround to make it possible (instead, Wrapper class (approach A) would be an easy to implement).

Coming back to using System.Tuple in our scenario:
Your controller action launching a view should be like:
public ActionResult PersonContactEdit()
{
..................
System.Tuple<PersonEntity, ContactEntity> personContactEntity = Tuple.Create(person object, contact object);
return View("EditPersonContact",   personContactEntity );
}

Create your view as strongly typed view by adding following line at top:
@model System.Tuple<LearnMVC4.Models.PersonEntity, LearnMVC4.Models.ContactEntity>

Once done, when you write @Model followed by dot (.) the intellisense will show you "Item1" and "Item2" both. Item1 corresponds to first type in tuple which is "PersonEntity", and Item2 corresponds to second type which is "ContactEntity". And you can now bind your controls, or use them in your view.
Example:

@Html.LabelFor(m => m.Item1.FullName)
Also, @Model.Item2.Email

So this is how we can pass different types of objects to single view, and can bind them.

Thursday, April 19, 2012

Investigation: Values do not retain in model while posting it from view to controller action in MVC

Scenario: My controller action is passing a model to the view, and displaying the fields on my view.
There are few fields which are non-editable (like, ID, etc), and are only for display purpose, so I have placed them directly on view.
There are few fields in that model which are not required to be displayed at all on view, so I have not placed them on view.
The problem is that, when a user clicks Submit to post the view to controller action, the model does not contain their original value for those fields.
How to fix it?

Fix: When you bind a model by passing it from control action to view, you should bind each and every field of the model in view. This will retain their values during HttpPost.

So if there are some fields you want to display them as read-only, or if you do not want to display them at all, then you should still bind them within view. Its necessary if you are posting the view to a controller action (using HttpPost)

The best way is to use hidden tag, using @Html.HiddenFor helper, if you do not want to display the field.
Or use @Html.DisplayFor helper, if you want to display the field in read-only mode.