Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I bind checkboxes to the List<int> property of a view model?

Tags:

asp.net-mvc

I've been reading the various posts on view models and check boxes, but my brain is starting to lock up and I need a little push in the right direction.

Here's my simplified view model. I have checkboxes that need to populate the lists with their values. I don't think this can happen automagically. I'm not sure how to bridge the gap between an array of string values and a List correctly. Suggestions?

public int AlertId { get; set; }

public List<int> UserChannelIds { get; set; }

public List<int> SharedChannelIds { get; set; }

public List<int> SelectedDays { get; set; }
like image 844
Doug Dawson Avatar asked Aug 31 '12 19:08

Doug Dawson


3 Answers

Have your View Model like this to represent the CheckBox item

public class ChannelViewModel 
{
  public string Name { set;get;}
  public int Id { set;get;}
  public bool IsSelected { set;get;}
}

Now your main ViewModel will be like this

public class AlertViewModel
{
  public int AlertId { get; set; }
  public List<ChannelViewModel> UserChannelIds { get; set; }      
  //Other Properties also her

  public AlertViewModel()
  {
    UserChannelIds=new List<ChannelViewModel>();       
  }

}

Now in your GET Action, you will fill the values of the ViewModel and sent it to the view.

public ActionResult AddAlert()
{
    var vm = new ChannelViewModel();

    //The below code is hardcoded for demo. you mat replace with DB data.
    vm.UserChannelIds.Add(new ChannelViewModel{ Name = "Test1" , Id=1});
    vm.UserChannelIds.Add(new ChannelViewModel{ Name = "Test2", Id=2 });

    return View(vm);
}

Now Let's create an EditorTemplate. Go to Views/YourControllerName and Crete a Folder called "EditorTemplates" and Create a new View there with the same name as of the Property Name(ChannelViewModel.cshtml)

Add this code ro your new editor template.

@model ChannelViewModel
<p>
  <b>@Model.Name</b>   :
  @Html.CheckBoxFor(x => x.IsSelected) <br />
  @Html.HiddenFor(x=>x.Id)
</p>

Now in your Main View, Call your Editor template using the EditorFor Html Helper method.

@model AlertViewModel
<h2>AddTag</h2>
@using (Html.BeginForm())
{
    <div>
        @Html.LabelFor(m => m.AlertId)
        @Html.TextBoxFor(m => m.AlertId)
    </div>    
    <div>  
      @Html.EditorFor(m=>m.UserChannelIds)         
    </div>    
    <input type="submit" value="Submit" />
}

Now when You Post the Form, Your Model will have the UserChannelIds Collection where the Selected Checkboxes will be having a True value for the IsSelected Property.

[HttpPost]
public ActionResult AddAlert(AlertViewModel model)
{
   if(ModelState.IsValid)
   {
      //Check for model.UserChannelIds collection and Each items
      //  IsSelected property value.
      //Save and Redirect(PRG pattern)
   }
   return View(model);
}
like image 54
Shyju Avatar answered Oct 15 '22 19:10

Shyju


Part of My View Model:

public List<int> UserChannelIds { get; set; }

public List<int> SharedChannelIds { get; set; }

public List<int> Weekdays { get; set; }

public MyViewModel()
{
    UserChannelIds = new List<int>();
    SharedChannelIds = new List<int>();
    Weekdays = new List<int>();
}

I used partial views to display my reusable checkboxes (I didn't know about editor templates at this point):

@using AlertsProcessor
@using WngAlertingPortal.Code
@model List<int>
@{
    var sChannels = new List<uv_SharedChannels>();
    Utility.LoadSharedChannels(sChannels);
}

<p><strong>Shared Channels:</strong></p>
<ul class="channel-list">
@{
    foreach (var c in sChannels)
    {
        string chk = (Model.Contains(c.SharedChannelId)) ? "checked=\"checked\"" : "";

        <li><input type="checkbox" name="SharedChannelIds" value="@c.SharedChannelId" @chk /> @c.Description (@c.Channel)</li>
    }
}

All three checkbox partial views are similar to each other. The values of the checkboxes are integers, so by lining up my view model List names with the checkbox names, the binding works.

Because I am working in int values, I don't feel like I need the extra class to represent the checkboxes. Only checked checkboxes get sent, so I don't need to verify they are checked; I just want the sent values. By initializing the List in the constructor, I should be avoiding null exceptions.

Is this better, worse or just as good as the other solution? Is the other solution (involving an extra class) best practice?

The following articles were helpful to me:

http://forums.asp.net/t/1779915.aspx/1?Checkbox+in+MVC3

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

like image 25
Doug Dawson Avatar answered Oct 15 '22 20:10

Doug Dawson


Binding list with view model

This site handles it very nicely

https://www.exceptionnotfound.net/simple-checkboxlist-in-asp-net-mvc/

enter image description here

public class AddMovieVM  
{
  [DisplayName("Title: ")]
  public string Title { get; set; }

public List<CheckBoxListItem> Genres { get; set; }

public AddMovieVM()
{
    Genres = new List<CheckBoxListItem>();
}
}
like image 20
Arun Prasad E S Avatar answered Oct 15 '22 19:10

Arun Prasad E S