0

I am facing trouble to create association between student and hobbies. i am showing my data though editable webgrid. webgrid has textboxes for name, dropdown for country selection and checkboxes for hobbies.

i want when user select each student hobbies...may be one or multiple and press submit button then i should be able to know each student's hobbies from student view model.

due to lack of knowledge i am not being able to do it.

this how my UI looks

enter image description here

This way i am generation checkboxes in each row webgrid.

    grid.Column(header: "Hobbies",
    format: @<text>
    @for (var i = 0; i < Model.Hobbies.Count; i++)
    {
        <div class="checkbox">
            @Html.HiddenFor(m => m.Hobbies[i].ID)
            @Html.HiddenFor(m => m.Hobbies[i].Name)
            @Html.CheckBoxFor(m => m.Hobbies[i].Checked)
            @Html.LabelFor(m =>m.Hobbies[i].ID, Model.Hobbies[i].Name)
        </div>
    }
    </text>)

my full razor code

@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>
            @for (var i = 0; i < Model.Hobbies.Count; i++)
            {
                <div class="checkbox">
                    @Html.HiddenFor(m => m.Hobbies[i].ID)
                    @Html.HiddenFor(m => m.Hobbies[i].Name)
                    @Html.CheckBoxFor(m => m.Hobbies[i].Checked)
                    @Html.LabelFor(m =>m.Hobbies[i].ID, Model.Hobbies[i].Name)
                </div>
            }
            </text>)
        ))

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

}

My controller and 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);
    }
}

My ViewModel code

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

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

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

        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",Checked=false},
            new Hobby{ID=2,Name="Hocky",Checked=false},
            new Hobby{ID=3,Name="Cricket",Checked=false}
        };

    }
}

My Model code

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

    public int CountryID { 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; }
    public bool Checked { get; set; }
}

please help me what i am trying to achieve. thanks

EDIT 1

    @for (var i = 0; i < Model.Hobbies.Count; i++)
    {
        <div class="checkbox">
            @Html.HiddenFor(m => m.Hobbies[i].ID)
            @Html.HiddenFor(m => m.Hobbies[i].Name)
            @Html.HiddenFor(m => m.Students[rowNum - 1].Hobbies[i].ID)
            @Html.CheckBoxFor(m => m.Students[rowNum - 1].Hobbies[i].Checked)
            @*@Html.CheckBoxFor(m => m.Hobbies[i].Checked)*@
            @Html.LabelFor(m =>m.Hobbies[i].ID, Model.Hobbies[i].Name)
        </div>
    }

enter image description here

Monojit Sarkar
  • 2,353
  • 8
  • 43
  • 94
  • 2
    Surely each `Student` has a collection of `Hobby` - i.e your `Student` class needs to contain `public IEnumerable Hobbies { get; set }`? –  Feb 20 '18 at 10:06
  • 2
    Now of course the code to generate the html in WebGrid is going to get far more uglier than it already is (but have have already told you in your previous questions to stop using it - and its pointless that your doing so since your not using its features like paging/sorting/filtering etc. And god know what its going to look like when you decide you want client side validation as well –  Feb 20 '18 at 10:14
  • 1
    Save yourself the extra overhead of WebGrid, and just create a `` element using `for` loops or an `EditorTemplate`. Not only will it be less code, it will be more readable and strongly typed to your model without 'magic strings'
    –  Feb 20 '18 at 10:15
  • @StephenMuecke ok i will add this code for student class IEnumerable Hobbies { get; set } but tell me how could i generate checkboxes in each grid row and when submit form then each student should have selected hobbies. please help with code example of razor side. thanks – Monojit Sarkar Feb 20 '18 at 10:21
  • 1
    Actually it will need to be `List` because you need a `for` loop in the view (I doubt you would be able to do sensible things like using an `EditorTemplate` in WebGrid). And you will need `@Html.HiddenFor(m => m.Students[rowNum - 1].Hobbies[i].Id)`, `@Html.CheckBoxFor(m.Students[rowNum - 1].Hobbies[i].Checked)` etc –  Feb 20 '18 at 10:26
  • if possible can you please post rectified code. from your little snippet i am not being able to understand what are the lines i need to change in razor. thanks – Monojit Sarkar Feb 20 '18 at 10:33
  • what EditorTemplate will do here? – Monojit Sarkar Feb 20 '18 at 10:34
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/165483/discussion-between-stephen-muecke-and-monojit-sarkar). –  Feb 20 '18 at 10:34
  • @StephenMuecke see my edit1 portion. i used your code but `@Html.HiddenFor(m => m.Students[rowNum - 1].Hobbies[i].ID)` in case of student hobbies id is always getting null....why? – Monojit Sarkar Feb 20 '18 at 10:46
  • Please keep to chat –  Feb 20 '18 at 10:47
  • @StephenMuecke i update my code as per your suggestion. it is working now. thanks – Monojit Sarkar Feb 20 '18 at 12:02
  • @StephenMuecke suppose if i have to work with EF and 4 table like Students, Country, HobbiesMaster and StudentHobbies then how could i define hobbies properties inside student class? in this scenario how each student could be associated with hobbies and how student selected hobbies can be inserted in studenthobbies table by EF? would you please share some idea. thanks – Monojit Sarkar Feb 20 '18 at 12:05
  • Please keep to chat! –  Feb 20 '18 at 12:07
  • @StephenMuecke i add my Edit2 section as answer as you suggested. thanks – Monojit Sarkar Feb 21 '18 at 10:47
  • i have one request sir. i posted a new one where i like to see how could i use editfor to create clean code. please see and share your valuable answer. https://stackoverflow.com/questions/48907525/asp-net-mvc-how-to-generate-html-table-using-editorfor-and-editor-template – Monojit Sarkar Feb 21 '18 at 19:42

1 Answers1

0

I could restructure my view model,model and razor view code. here i like to give my updated code which is working fine.

This way i generate checkboxes in forloop.

grid.Column(header: "Hobbies",
format: @<text>
@for (var i = 0; i < Model.Students.FirstOrDefault().Hobbies.Count; i++)
{
    <div class="checkbox">
        @Html.HiddenFor(m => m.Students[rowNum - 1].Hobbies[i].ID)
        @Html.HiddenFor(m => m.Students[rowNum - 1].Hobbies[i].Name)
        @Html.CheckBoxFor(m => m.Students[rowNum - 1].Hobbies[i].Checked)
        @Html.LabelFor(m => m.Students[rowNum - 1].Hobbies[i].Name, Model.Students.FirstOrDefault().Hobbies[i].Name)
    </div>
}
</text>)

view model and model class code

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



    public StudentListViewModel()
    {
        Students = new List<Student>
        {
            new Student
            {
                ID=1,Name="Keith",CountryID=0,
                Hobbies= new List<Hobby>
                {
                    new Hobby{ID=1,Name="Football",Checked=false},
                    new Hobby{ID=2,Name="Hocky",Checked=false},
                    new Hobby{ID=3,Name="Cricket",Checked=false}
                }

            },

            new Student
            {
                ID=2,Name="Paul",CountryID=2,
                Hobbies= new List<Hobby>
                {
                    new Hobby{ID=1,Name="Football",Checked=false},
                    new Hobby{ID=2,Name="Hocky",Checked=false},
                    new Hobby{ID=3,Name="Cricket",Checked=false}
                }
            },

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

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

    }
}

Model code

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

    public int CountryID { get; set; }
    public IList<Hobby> Hobbies { 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; }
    public bool Checked { get; set; }
}

Bit Different way done again

The same UI i also developed with html table. here i am sharing the razor code and rest of the model and model view code is same as before.

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

<h2>CREATE TABULAR UI WITH HTML TABLE</h2>

@using (Html.BeginForm("Index", "HtmlTable", FormMethod.Post))
{
    <div class="form-group">
        <div class="col-md-12 table-responsive">
            <table class="table table-bordered table-hover">
                <tr>
                    <th>
                        Row No
                    </th>
                    <th>
                        ID
                    </th>
                    <th>
                        Name
                    </th>
                    <th>
                        Country
                    </th>
                    <th>
                        Hobbies
                    </th>
                    <th>
                        Sex
                    </th>
                </tr>
                }
                @for (int x=0; x<=Model.Students.Count-1;x++)
                {

                    <tr>
                        <td>
                            <label>@(x+1)</label>
                        </td>
                        <td>
                            @Html.TextBoxFor(m => m.Students[x].ID)
                        </td>
                        <td>
                            @Html.TextBoxFor(m => m.Students[x].Name)
                        </td>
                        <td>
                            @Html.DropDownListFor(m => m.Students[x].CountryID,
                              new SelectList(Model.Country, "ID", "Name",  Model.Students[x].CountryID),
                             "-- Select Countries--", new { id = "cboCountry", @class = "edit-mode" })
                        </td>
                        <td>
                            @for (var i = 0; i < Model.Students.FirstOrDefault().Hobbies.Count; i++)
                            {
                                <div class="checkbox">
                                    @Html.HiddenFor(m => m.Students[x].Hobbies[i].ID)
                                    @Html.HiddenFor(m => m.Students[x].Hobbies[i].Name)
                                    @Html.CheckBoxFor(m => m.Students[x].Hobbies[i].Checked)
                                    @Html.LabelFor(m => m.Students[x].Hobbies[i].Name, Model.Students[x].Hobbies[i].Name)
                                </div>
                            }

                        </td>
                        <td>
                            @for (var i = 0; i < Model.Sex.Count; i++)
                            {
                                <div class="checkbox">
                                    @Html.HiddenFor(m => Model.Sex[i].ID)
                                    @Html.HiddenFor(m => Model.Sex[i].SexName)
                                    @Html.RadioButtonFor(m => m.Students[x].SexID, Model.Sex[i].ID)
                                    @Html.LabelFor(m => m.Students[x].SexID, Model.Sex[i].SexName)
                                </div>
                            }
                        </td>
                    </tr>
                }
            </table>
        </div>

        <input type="submit" value="Submit" />
    </div>
}
  [1]: https://stackoverflow.com/users/3559349/stephen-muecke
Monojit Sarkar
  • 2,353
  • 8
  • 43
  • 94