4

I'm practicing with this project where I need to show to the user a list of clients and a checkbox for each client so he can select some and then click a button.

I managed to make the list and I can see one checkbox for every line in my list.

The problem is:

I don't know how to make each checkbox be related to each item in my list... Currently they working like a single checkbox for the entire list.

I'm very new to C# and maybe I'm just doing something stupid here, so could you please help me with this?

Also, how would I iterate the list to check which ones are selected?

When debugging I see the checkbox as a single element, not one for each item in my list

Here is my code:

My viewModel:

 public class TransferViewModel
{
    public TransferViewModel() 
    {
        Clients = new List<Client>();
    }

    public virtual ICollection<Client> Clients { get; set; }

    [DisplayName("ID")]
    public int? Id { get; set; }

    [DisplayName("Transferir de")]
    public string TransferFrom { get; set; }

    [DisplayName("Transferir para")]
    public string TransferTo { get; set; }

    [DisplayName("Selecionado")]
    public bool IsSelected { get; set; }

    [DisplayName("Categoria do Cliente")]
    public virtual ClientCategory Category { get; set; }

    [DisplayName("Categoria do Cliente")]
    public int? CategoryId { get; set; }

    [DisplayName("Razão Social")]
    public string OfficialName { get; set; }

    [DisplayName("Nome Fantasia")]
    public string DisplayName { get; set; }

    [DisplayName("Responsável")]
    public string AssignedToLogin { get; set; }

    [DisplayName("Excluído")]
    public bool IsDeleted { get; set; }

    [DisplayName("Ultima atividade")]
    public DateTime? LastInteractionOn { get; set; }

}

My Controller:

           [ViewBagListOfUsers]
    // GET: ActivityTypes/Create
    public ActionResult TransferSpecificClients(TransferViewModel model)
    {
        var selectedUserFrom = model.TransferFrom;
        var selectedUserTo = model.TransferTo;
        var query = db.Clients as IQueryable<Client>;

        if (selectedUserFrom!=null)
        {
            model.Clients = query
            .Where(p => p.AssignedToLogin == selectedUserFrom)
            .ToArray();

        }


        if ((selectedUserTo != null)&&(selectedUserFrom != null))
        {

                 //do something if the client is selected ...

        }
        return View( model);

And my view:

@model EFGEREN.App.Models.ViewModels.Clients.TransferViewModel
@using EFGEREN.App.Models.Entities
@using System.Linq
@using System.Web.Mvc
@using Resources

@{
    ViewBag.Title = "TransferSpecificClients";
    IEnumerable<SelectListItem> usersListFrom = ViewBag.UserList;
    IEnumerable<SelectListItem> usersListTo = ViewBag.UserList;

}

<h2>TransferSpecificClients</h2>



@using (Html.BeginForm())
{
    @Html.DisplayNameFor(model => model.TransferFrom)
    @Html.DropDownListFor(m => m.TransferFrom, usersListFrom, Expressions.DropDownListSelectOneX, new { @class = "form-control" })


<div class="controls well well-sm">
    <button type="submit" value="Filtrar" class="btn btn-success"><i class="glyphicon glyphicon-ok"></i>@("Filtrar")</button>
</div>


<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.IsSelected)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.CategoryId)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.OfficialName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.DisplayName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.AssignedToLogin)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.LastInteractionOn)
        </th>
        <th></th>
    </tr>



@foreach (var item in Model.Clients) {
    <tr>

        <td>
            @Html.CheckBoxFor(m => m.IsSelected, new { @checked = "checked" })
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.CategoryId)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.OfficialName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.DisplayName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.AssignedToLogin)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.LastInteractionOn)
        </td>

    </tr>}


</table>

@Html.DisplayNameFor(model => model.TransferTo)
@Html.DropDownListFor(m => m.TransferTo, usersListTo, Expressions.DropDownListSelectOneX, new { @class = "form-control" })
<div class="controls well well-sm">
    <button type="submit" value="Transferir" class="btn btn-success"><i class="glyphicon glyphicon-ok"></i>@("Transferir")</button>
</div>
}
  • You cannot use a `foreach` loop (refer the dupe). And remove your ` new { @checked = "checked" }` code. The `CheckBoxFor()` method determines is its selected based on the value of the property. –  Apr 14 '16 at 02:54

1 Answers1

3

There are some content on SF about how to bind collections, but basically you should use a structure like this on your view:

@foreach (var item in Model.Clients) {

// Create a value to be used as index of your elements
var guid = @Guid.NewGuid().ToString();

// Define the prefix of each element from this point
ViewData.TemplateInfo.HtmlFieldPrefix = "Clientes[" + guid + "]";

    <tr>
        <td>
            <input type='hidden' name='Clientes.Index' value='@guid'>
            @Html.CheckBoxFor(m => m.IsSelected, new { @checked = "checked" })
        </td>
     </tr>
}

Mode details about how model binding works with collections:

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

To check which elements are checked on server-side you should use LINQ as you already are using:

var clientes = model.Clientes.Select(x => x.IsSelected == true).ToList();

Hope it helps.

Rodrigo Leite
  • 874
  • 8
  • 15
  • Thank you Rodrigo. Your answer helped me alot. The problem was that I messed my viewmodel and was using a single bool property to an entire list of Clients. I just corrected my model (made it a list of: bool + Clients) and now it works. – Diego Gomes Santos Apr 15 '16 at 01:33
  • 1
    Inside the foreach in the Razor view, the `m => m.` lambda only seems to bind to the model, not the the item in the loop – Douglas Gaskell Jun 13 '18 at 20:34
  • Inside the foreach in the Razor view, the `m => m.` lambda only seems to bind to the model, not the the item in the loop – Douglas Gaskell Jun 13 '18 at 20:35
  • My issue is exactly Douglas's. How do you Bind it to the item in the loop? – footose Jan 04 '19 at 02:53