0

I have developed a tabular UI with webgrid. i am showing student information through webgrid. i am showing multiple checkboxes for hobbies in each row of webgrid. when i select hobbies and click submit button then i saw hobbies selection is not going to action.

i guess there is my mistake in view model class design. please have a look at my code and tell me which area i need to change in code.

i want all hobbies should go to action when i click submit button and selected hobbies also should post to action for each student. a student may have multiple hobbies selected.

here is my viewcode

@model MVCCRUDPageList.Models.StudentListViewModel
@{
    ViewBag.Title = "Index";
}

<h2>Student View Model</h2>

@using (Html.BeginForm("Index", "WebGridMoreControls", FormMethod.Post))
{
    var grid = new WebGrid(Model.Students, canSort: false, canPage: false);
    var rowNum = 0;
    var SelectedHobbies = 0;

    <div id="gridContent" style=" padding:20px; ">
        @grid.GetHtml(
        tableStyle: "table",
        alternatingRowStyle: "alternate",
        selectedRowStyle: "selected",
        headerStyle: "header",
        columns: grid.Columns
        (
            grid.Column(null, header: "Row No", format: item => rowNum = rowNum + 1),
            grid.Column("ID", format: (item) => @Html.TextBoxFor(m => m.Students[rowNum - 1].ID, new { @class = "edit-mode" })),
            grid.Column("Name", format: (item) => @Html.TextBoxFor(m => m.Students[rowNum - 1].Name, new { @class = "edit-mode" })),

             grid.Column("Country", format: (item) =>
                  @Html.DropDownListFor(x => x.Students[rowNum - 1].CountryID,
                  new SelectList(Model.Country, "ID", "Name", item.CountryID),
                 "-- Select Countries--", new { id = "cboCountry", @class = "edit-mode" })),

            grid.Column(header: "Hobbies",
            format: @<text>

            Hobbies
            @foreach (var hobby in Model.Hobbies)
            {
                <div class="checkbox">
                    <label>
                        @Html.HiddenFor(e => e.Hobbies)
                        <input type="checkbox"
                               name="Hobbies"
                               value="@hobby.ID" /> @hobby.Name
                    </label>
                 </div>
            }
            </text>)
        ))

        <input type="submit" value="Submit" />
    </div>

}

Action code

public class WebGridMoreControlsController : Controller
{
    // GET: WebGridMoreControls
    public ActionResult Index()
    {
        StudentListViewModel osvm = new StudentListViewModel();
        return View(osvm);
    }

    [HttpPost]
    public ActionResult Index(StudentListViewModel oStudentListViewModel)
    {
        return View(oStudentListViewModel);
    }
}

View model code

public class StudentListViewModel
{
    public IList<Student> Students { get; set; }
    public List<Country> Country { get; set; }

    public IList<Hobby> SelectedHobbies { get; set; }
    public IList<Hobby> Hobbies { get; set; }

    public StudentListViewModel()
    {
        Students = new List<Student>
        {
            new Student{ID=1,Name="Keith",CountryID=0,Hobby=0},
            new Student{ID=2,Name="Paul",CountryID=2,Hobby=0},
            new Student{ID=3,Name="Sam",CountryID=3,Hobby=0}
        };

        Country = new List<Country>
        {
            new Country{ID=1,Name="India"},
            new Country{ID=2,Name="UK"},
            new Country{ID=3,Name="USA"}
        };

        Hobbies = new List<Hobby>
        {
            new Hobby{ID=1,Name="Football"},
            new Hobby{ID=2,Name="Hocky"},
            new Hobby{ID=3,Name="Cricket"}
        };

    }
}

Model code

public class Student
{
    public int ID { get; set; }
    [Required(ErrorMessage = "First Name Required")]
    public string Name { get; set; }

    public int CountryID { get; set; }
    public int Hobby { get; set; }
}

public class Country
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class Hobby
{
    public int ID { get; set; }
    public string Name { get; set; }
} 

please help me to rectify view, viewmodel and model class code. thanks

Monojit Sarkar
  • 2,353
  • 8
  • 43
  • 94
  • 1
    For a start, look at the html generated by `@Html.HiddenFor(e => e.Hobbies)` (in particular the `value` attribute to understand why that will not work, and your `Hobbies` property will always be `null` in the POST method. Ditto for your manual checkbox (a collection of complex objects cannot be bound to a `string` or an `int[]`) To understand how to bind a collection of checkboxes, refer [this answer](https://stackoverflow.com/questions/29542107/pass-list-of-checkboxes-into-view-and-pull-out-ienumerable/29554416#29554416) –  Feb 19 '18 at 22:05

1 Answers1

0

Add a viewmodel for Hobby:

public class HobbyViewModel
{
    public int ID { get; set; }
    public string Name { get; set; }
    public bool Checked { get; set; }
}

Modify your StudentListViewModel as following:

 public class StudentListViewModel
    {
        public IList<Student> Students { get; set; }
        public List<Country> Country { get; set; }
        public IList<HobbyViewModel> Hobbies { get; set; }

        public StudentListViewModel()
        {
            Students = new List<Student>
            {
                new Student{ID=1,Name="Keith",CountryID=0,Hobby=0},
                new Student{ID=2,Name="Paul",CountryID=2,Hobby=0},
                new Student{ID=3,Name="Sam",CountryID=3,Hobby=0}
            };

            Country = new List<Country>
            {
                new Country{ID=1,Name="India"},
                new Country{ID=2,Name="UK"},
                new Country{ID=3,Name="USA"}
            };

            Hobbies = new List<HobbyViewModel>
            {
                new HobbyViewModel{ID=1,Name="Football"},
                new HobbyViewModel{ID=2,Name="Hocky"},
                new HobbyViewModel{ID=3,Name="Cricket"}
            };

        }

Replace the foreach in the view as following:

 @for (var i = 0; i < Model.Hobbies.Count; i++)
                            {
                                <div class="checkbox">
                                    @Html.HiddenFor(m => m.Hobbies[i].ID)
                                    @Html.CheckBoxFor(m => m.Hobbies[i].Checked)
                                    @Html.LabelFor(m => m.Hobbies[i].Checked, Model.Hobbies[i].Name)
                                </div>
                            }
Adnan Niloy
  • 469
  • 11
  • 18
  • thanks for answer but how could associate hobbies with each student. so when i will submit form then from server side i should be able to know what each student's hobbies. please tell me how could i refactor viewmodel and class code with razor view code. – Monojit Sarkar Feb 20 '18 at 09:31
  • i have posted another question. please have a look. https://stackoverflow.com/questions/48882484/asp-net-mvc-how-to-associate-hobbies-with-each-student – Monojit Sarkar Feb 20 '18 at 10:01
  • I see Stephen is helping you. Please try to follow his instructions. He is a legend here :) @MonojitSarkar – Adnan Niloy Feb 20 '18 at 10:45