3

I am trying to bind unknown amount of checkboxes to a list of booleans. After hours of searching I havn't found any solution.

This is the relevent part of code in my view:

        @foreach (Device d in Data.GetDevices())
    {
        <label asp-for="NewRegistration.Devices">@d.Name</label>
        <input asp-for="NewRegistration.Devices" class="checkbox" type="checkbox" />
    }

The loop works but when i changed the type if the input to checkbox it gave me this exeption:

InvalidOperationException: Unexpected 'asp-for' expression result type 'System.Collections.Generic.List`1[[System.Boolean, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]' for . 'asp-for' must be of type 'System.Boolean' if 'type' is 'checkbox'.

The list i try to put my data in contains the following code:

        private List<bool> _devices;

    public List<bool> Devices
    {
        get { return _devices; }
        set {_devices = value; }
    }

So my question is how do I add values from these checkboxes into my list of booleans. When i don't specify the type of the input's, I dont get any errors but the type of the input is text. If i enter true or false in these inputboxes my code works fine. But I want a checkbox instead of asking the user to enter true or false.

Thank you for your time!

edit: My question proves hard to explain. I'm validating the form and binding it to an instance of the registration class defined in a presentation model PMRegistration. I will put the full code below if the snippets are not clear enough

Registration class:

  public class Registration
{

    public int Id { get; set; }
    [Required(ErrorMessage = "required field")]
    [MaxLength(50, ErrorMessage = "To long")]
    [DisplayName("Name")]
    public string Name { get; set; }
    [Required(ErrorMessage = "required field")]
    [MaxLength(50, ErrorMessage = "To long")]
    [DisplayName("Firstname")]
    public string FirstName { get; set; }
    [Required(ErrorMessage = "required field")]
    [Range(1,110 ,ErrorMessage = "To long")]

    public string Age { get; set; }
    [Required(ErrorMessage = "required field")]
    [EmailAddress(ErrorMessage ="Not a valid email address")]
    public string Email { get; set; }
    [Required(ErrorMessage = "required field")]
    [DisplayName("slot1")]
    public int Slot1SessionId { get; set; }
    [Required(ErrorMessage = "required field")]
    [DisplayName("slot2")]
    public int Slot2SessionId { get; set; }
    [Required(ErrorMessage = "required field")]
    [DisplayName("slot3")]
    public int Slot3SessionId { get; set; }


    private List<bool> _devices;

    public List<bool> Devices
    {
        get { return _devices; }
        set {_devices = value; }
    }

    [Required(ErrorMessage = "required field")]
    [DisplayName("Organization")]
    public int OrganizationId { get; set; }
    public bool ClosingParty { get; set; }



}

My view looks like this:

        @using week3.Models;
@model week3.Models.PresentationModels.PMRegistration
<div>
    <h1>New Registration</h1>
    <h2>registration</h2>
</div>
<form class="form-group" asp-controller="Registration" asp-action="New" method="post">
    <div>
        <label asp-for="NewRegistration.Name">Name:</label>
        <input asp-for="NewRegistration.Name" class="form-control" value="@Model.NewRegistration.Name" />
        <span asp-validation-for="NewRegistration.Name" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="NewRegistration.FirstName">Firstname:</label>
        <input asp-for="NewRegistration.FirstName" class="form-control" value="@Model.NewRegistration.FirstName" />
        <span asp-validation-for="NewRegistration.FirstName" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="NewRegistration.Age">Age:</label>
        <input asp-for="NewRegistration.Age" class="form-control" value="@Model.NewRegistration.Age" />
        <span asp-validation-for="NewRegistration.Age" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="NewRegistration.Email">Email:</label>
        <input asp-for="NewRegistration.Email" class="form-control" value="@Model.NewRegistration.Email" />
        <span asp-validation-for="NewRegistration.Email" class="text-danger"></span>
    </div>
    <div>
        <div>Pick your sessions</div>
        <label asp-for="NewRegistration.Slot1SessionId" class="form-label">Slot1:</label>
        <select asp-for="NewRegistration.Slot1SessionId" class="form-control" asp-items="@Model.getSessionNamesBySlot(1)" value="@Model.NewRegistration.Slot1SessionId"></select>
        <span asp-validation-for="NewRegistration.Slot1SessionId" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="NewRegistration.Slot2SessionId">Slot2:</label>
        <select asp-for="NewRegistration.Slot2SessionId" class="form-control" asp-items="@Model.getSessionNamesBySlot(2)" value="@Model.NewRegistration.Slot2SessionId"></select>
        <span asp-validation-for="NewRegistration.Slot2SessionId" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="NewRegistration.Slot3SessionId">Slot3:</label>
        <select asp-for="NewRegistration.Slot3SessionId" class="form-control" asp-items="@Model.getSessionNamesBySlot(3)" value="@Model.NewRegistration.Slot3SessionId"></select>
        <span asp-validation-for="NewRegistration.Slot3SessionId" class="text-danger"></span>
    </div>
    
        <div>are you wearing dangerous accessoires?</div>

        @foreach (Device d in Data.GetDevices())
        {
            
            <label asp-for="NewRegistration.Devices[0]">@d.Name</label>
            <input asp-for="NewRegistration.Devices[0]" class="checkbox" type="checkbox"  />
        }
    <div>
        <label asp-for="NewRegistration.OrganizationId">Organization:</label>
        <select asp-for="NewRegistration.OrganizationId" asp-items="@Model.getOrganizations()" class="form-control"></select><br />
    <span asp-validation-for="NewRegistration.OrganizationId" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="NewRegistration.ClosingParty">Are you coming to the closing party?</label>
        <input asp-for="NewRegistration.ClosingParty" />
        <span asp-validation-for="NewRegistration.ClosingParty" class="text-danger"></span>
    </div>
            <input type="submit" class="btn btn-default" value="Register" />
</form>

4
  • Possible duplicate of MVC 6 Tag Helpers and foreach Commented Jan 6, 2017 at 18:12
  • @foreach (Device d in Data.GetDevices()) are you calling executing code from within razor instead of pushing a model populated with data? Commented Jan 6, 2017 at 18:13
  • Shouldn't it be something like asp-for="@d.NameOfBooleanProperty" on the <input> ? Commented Jan 6, 2017 at 18:33
  • A presentation model is passed on for binding. But the Data is where my data is stored. So i get all devices in my data class to loop over the checkboxes that need to be created. Commented Jan 6, 2017 at 18:42

1 Answer 1

6

Reason for error

Your error is because you have this: asp-for="NewRegistration.Devices". That is not valid because the tag is input of type checkbox so asp-for is expecting a boolean and you are sending it a list of booleans.

Solution

This will create checkboxes for your devices:

@foreach (Device d in Data.GetDevices())
{
    @Html.CheckBox(item);
}

But my assumption is you want the user to select these checkboxes and then post them back to you, if that is the case then you need to do this:

You need to create a model like this:

public class Device
{
    public string Name { get; set; }
}
public class DevicesCollectionModel
{
    public List<Device> AvailableDevices { get; set; }
    public List<Device> SelectedDevices { get; set; }
}

Populate the DevicesCollectionModel.AvailableDevices and pass it to your view. Then in your view, create a checkbox for each device in AvailableDevices. Pay attention to the name attribute of the input tag below:

@foreach (var item in Model.AvailableDevices)
{
<div class="checkbox">
    <label>
        <input type="checkbox"
                name="SelectedDevices"
                value="@item.Name" /> @item.Name
        </label>
    </div>
}

Then in your controller, in post, you will need to access the SelectedDevices property to figure out what the user has selected.

Furthermore, you can create separate models: one for sending to the user and one the controller receives from the user. The model you pass to your view can just have the AvailableDevices and the model you get in your controller on post can have SelectedDevices. MVC will bind it for you using the name attribute from the input tag.

Sign up to request clarification or add additional context in comments.

4 Comments

I realise the way i described my problem might be a little confusing. The devices have nothing to do with the output of the list. I added the full code if your still intrested.
What do you mean the devices have nothing to do with the output of the code? You are using the list to create checkboxes so how does it not have anything to do with it?
Sorry i did not get your code! I think your code is the solution I just did not read it correctly! Thank you verry much!
Absolute best answer for adding a checkbox list and binding selected values. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.