How to know the selected checkboxes from within th

2020-01-26 11:59发布

问题:

I have many-to-many relationship between Student and Course. The linking entity set is Enrollment. For the sake of simplicity, they are all defined as follows.

Models

public class Course
{
    public int Id { get; set; }
    public string Title { get; set; }

    public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class Enrollment
{
    public int Id { get; set; }
    public int StudentId { get; set; }
    public int CourseId { get; set; }

    public virtual Student Student { get; set; }
    public virtual Course Course { get; set; }
}

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Enrollment> Enrollments { get; set; }
}

ViewModels

public class StudentCourseVM
{
    public Student Student { get; set; }
    public IEnumerable<Course> SelectedCourses { get; set; }
    public IEnumerable<Course> AvailableCourses { get; set; }
}

Controllers

    public IActionResult Create()
    {
        var availableCourses = context.Courses;
        return View(new StudentCourseVM { AvailableCourses = availableCourses });
    }


    [HttpPost]
    public async Task<IActionResult> Create(StudentCourseVM sc)
    {
        if (ModelState.IsValid)
        {
            // What should I do here?
            // ======================
            await context.SaveChangesAsync();
            return RedirectToAction("Index");
        }
        return View(sc);
    }

Views

@model MasterDetails.ViewModels.StudentCourseVM
<form asp-action="Create">
    <div>
        <label asp-for="@Model.Student.Name"></label>
        <input asp-for="@Model.Student.Name" />
    </div>
    <div>
        <label asp-for="@Model.Student.Enrollments"></label><br />
        @foreach (var course in Model.AvailableCourses)
        {
            <input type="checkbox" name="@course.Title" id="@course.Id" /> @course.Title <br />
        }
    </div>
    <input type="submit" value="Create" />
</form>

Questions

How to know the selected check boxes from within the HttpPost Create action method?

回答1:

You can use Editor Templates to do this.

First, create a new class for the course selection and update your view model to have a collection of that class.

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

public class StudentCourseVM
{
    public int StudentId { set; get; }       
    public IEnumerable<SelectedCourse> SelectedCourses { get; set; }
}

You do not need to copy and paste all the properties from your entity model to your view model. View model needs only those properties which the view absolutely need. I am assuming you want to assign courses to a specific student

Now go to your ~/Views/YourControllerName and create a directory called EditorTemplates. Create a new razor file there and give the name SelectedCource.cshtml

Paste this code to the new file

@model SelectedCourse
<label>@Model.Name</label>
<input asp-for="IsSelected"/>
<input type="hidden" asp-for="Id" />

Now in your GET action, create an object of the view model, load the SelectedCourses collection and send it to the view.

public IActionResult Create()
{
    // I hard coded the student id and the courses here.
    // you may replace it with real data.
    var vm = new StudentCourseVM { StudentId = 12 }; 
    //Assuming we are assigning courses to the student with id 12
    vm.SelectedCourses = new List<SelectedCourse>()
    {
        new SelectedCourse {Id = 1, Name = "CSS"},
        new SelectedCourse {Id = 2, Name = "Swift"},
        new SelectedCourse {Id = 3, Name = "IOS"},
        new SelectedCourse {Id = 4, Name = "Java"}
    };
    return View(vm);
}

Now in your main view(Create.cshtml) which is strongly typed to StudentCourseVM,Use EditorFor helper method on the SelectedCourses property.

@model StudentCourseVM
<form asp-action="Create">   
    @Html.EditorFor(f=>f.SelectedCourses)
    <input type="hidden" asp-for="StudentId"/>
    <input type="submit"/>
</form>

The Editor template will execute code in the editor template file for each item in the SelectedCourses collection. So you will have the course name and a checkbox visible to the user.

In your HttpPost action method, you can use the same view model as the parameter. When the form is submitted, you may loop through the items in SelectedCourses property check the IsSelected property value. The courses user selected in the ui will have a true value.

[HttpPost]
public IActionResult Create(StudentCourseVM model)
{
    var studentId = model.StudentId; 
    foreach (var modelSelectedCourse in model.SelectedCourses)
    {
        if (modelSelectedCourse.IsSelected)
        {
            //this one is selected. Save to db
        }
    }
    // to do : Return something
}

Pre-selecting some checkboxes on page load

Sometimes you want to pre select some checkboxes when the page loads (Ex : For your edit screen you want to show already saved courses as checked). To do this, you simply need to set the IsSelected property of the corresponding SelectedCourse object to true in your GET action method.

public IActionResult Edit(int id)
{
    // I hard coded the student id and the courses here.
    // you may replace it with real data.
    var vm = new StudentCourseVM { StudentId = id }; 
    //Assuming we are assigning courses to the student with id 12
    vm.SelectedCourses = new List<SelectedCourse>()
    {
        new SelectedCourse {Id = 1, Name = "CSS"},
        new SelectedCourse {Id = 2, Name = "Swift", IsSelected = true },
        new SelectedCourse {Id = 3, Name = "IOS", IsSelected = true },
        new SelectedCourse {Id = 4, Name = "Java"}
    };
    return View(vm);
}

The above code will pre select the checkboxes for Swift and IOS.