Jeff
Jeff

Reputation: 104

Bind Checkboxlist to model

I'm working on an app for a cycling team. I have to add riders to a ride. To do this I want the user te select the date of a ride, select a value for the point of this ride an then have a list of the members of the team where the user selects which member participated on the ride.

It works fine until I post the form. when I debug my model in the controler the list of Riders in de model counts 4 riders (which is correct as I have 4 riders in my Db for testing) but the riders are null when I check the list.

Can anyone help me, I dont know what I'm doing wrong.

this are the viewmodels I use:

public class RiderViewModel
{

    public string Id { get; set; }
    public string FulllName { get; set; }
    public bool IsChecked { get; set; }
}


public class RideViewModel
{
    public string RideId { get; set; }
    [Display(Name = "Datum")]
    [DataType(DataType.Date)]
    [Required(ErrorMessage = "Datum is verplicht")]
    public DateTime Date { get; set; }
    [Display(Name = "Aantal punten")]
    [Required(ErrorMessage = "Een waarde voor het puntenaantal is verplicht")]
    public int Punten { get; set; }
    [Display(Name = "Leden")]
    public  List<RiderViewModel> Riders { get; set; }
}

this is my controler:

//POST Rides/Create
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(RideViewModel model)
    {
        if (ModelState.IsValid)
        {
            var db = new ApplicationDbContext();
            var riders = new List<ApplicationUser>();

            foreach(RiderViewModel r in model.Riders)
            {
                var user = db.Users.FirstOrDefault(u => u.Id == r.Id);
                if(user == null)
                {
                    ModelState.AddModelError(string.Empty, "Er is een Fout opgetreden bij het selecteren van de leden. contacteer de systeembeheerder indien het probleem blijft bestaan");
                    return View(model);
                }
                riders.Add(user);
            }

            var ride = new Ride
            {
                Date = model.Date,
                Punten = model.Punten,
                Riders = riders
            };

            db.Rides.Add(ride);
            db.SaveChanges();

            return RedirectToAction("Index", "AdminPanel");
        }
        return View(model);
    }

and this is the view:

using (Html.BeginForm()) 
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
    <h4>Ride</h4>
    <hr />
    <div class="form-group">
        @Html.LabelFor(model => model.Date, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Date, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Date, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Punten, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Punten, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Punten, "", new { @class = "text-danger" })
        </div>
    </div>
    <div class="form-group">
        @Html.Label("Leden", htmlAttributes: new { @class = "control-label col-md-2"})
        <div class="col-md-10">
            @for (var i = 0; i < Model.Riders.Count(); i++)
            {
                <div class="col-md-10">
                    @Html.HiddenFor(model => model.Riders[i])                        
                    @Html.CheckBoxFor(model => model.Riders[i].IsChecked)
                    @Html.LabelFor(model => model.Riders[i].IsChecked, Model.Riders[i].FulllName)
                 </div>
            }
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</div>

}

Thanx a lot.

grtz Jeff

Upvotes: 2

Views: 89

Answers (2)

user3559349
user3559349

Reputation:

Your usage of

@Html.HiddenFor(model => model.Riders[i])

is creating a hidden input for a complex property which is typeof RiderViewModel. If you inspect the html, it will be something like

<input type="hidden" id="Riders_0_" name="Riders[0]" value="someAssembly.RiderViewModel" />

When you submit, the DefaultModelBinder tries to set model.Riders[0] to the value someAssembly.RiderViewModel which fails and so model.Riders[0] is null

Assuming you want to generate a hidden input for the ID property, change it to

@Html.HiddenFor(model => model.Riders[i].ID)

Upvotes: 1

Alan Macgowan
Alan Macgowan

Reputation: 481

You can use a EditorTemplate for this, just add a new file in the EditorTemplates folder named RiderViewModel :

             @model RiderViewModel

             <div class="col-md-10">
                @Html.HiddenFor(model => model.Id)                        
                @Html.CheckBoxFor(model => model.IsChecked)
                @Html.LabelFor(model => model.IsChecked, Model.FulllName)
             </div>

Then in the view just call the EditorFor:

             @Html.EditorFor(m => m.Riders)

Upvotes: 1

Related Questions