Answered by:
Getting back empty viewmodel

Question
-
User25974107 posted
Hi!
What I need is to get back a list of checkboxes that are not selected. I have a viewmodel:
public class ProductInShopsCheckboxViewModel { public string ShopName { get; set; } = default!; public List<CheckboxViewModel>? Checkboxes { get; set; } = new List<CheckboxViewModel>(); } public class CheckboxViewModel { public bool IsSelected { get; set; } = true; public string ProductName { get; set; } = default!; public long Barcode { get; set; } public Guid ProductId { get; set; } }
Then in controller, I fill the checkboxes list:
public async Task<IActionResult> Assortment(Guid id) { if (id == null) { return NotFound(); } IEnumerable<ProductInShop> products = _uow.ProductInShops.GetAllProducts(id); ProductInShopsCheckboxViewModel vm = new ProductInShopsCheckboxViewModel { ShopName = _uow.ProductInShops.GetShopName(id) }; foreach (var p in products) { vm.Checkboxes!.Add(new CheckboxViewModel { ProductName = p.Product!.ProductName, Barcode = p.Product.Barcode, ProductId = p.ProductId }); } return View(vm); }
and finally I generate the checkboxes in my view:
<form asp-action="Assortment" method="post"> @for (var i = 0; i < Model.Checkboxes!.Count; i++) { <div class="[ form-group ]"> <input name="products" type="checkbox" id="@Model.Checkboxes[i].ProductId" value="@Model.Checkboxes[i].ProductName"/> <div class="[ btn-group ]"> <label asp-for="@Model">@Model.Checkboxes[i].ProductName</label> </div> </div> } <div class="form-group"> <input type="submit" value="Send email" class="btn btn-primary"/> </div> </form>
This is working very well. However when I ask the viewmodel back in my controller, it's empty.
public async Task<IActionResult> Assortment(Guid id, ProductInShopsCheckboxViewModel vm) { Console.WriteLine(vm.Checkboxes!.Count); //size is 0 }
If I ask from controller string [ ] products, I get all the checked products, but it's useless for me without barcodes.
Any advice is appreciated.
Thursday, July 2, 2020 5:00 PM
Answers
-
User348806598 posted
There is a better way of doing this without naming the names of controls yourself. To use helper methods like below-
@model MVCSamples.Models.ProductInShopsCheckboxViewModel @{ ViewData["Title"] = "Assortment"; } <h1>Assortment</h1> <form action="_2168657_Getting_back_empty_viewmodel/AssortmentSave" method="post"> @for (var i = 0; i < Model.Checkboxes!.Count; i++) { <div class="[ form-group ]"> @Html.HiddenFor(model => model.Checkboxes[i].ProductId) <label>@Html.CheckBoxFor(model => model.Checkboxes[i].IsSelected)</label> @Html.DisplayFor(model => model.Checkboxes[i].ProductName) <label>Bar code : @Model.Checkboxes[i].Barcode</label> </div> } <div class="form-group"> <input type="submit" value="Send email" class="btn btn-primary" /> </div> </form>
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, July 2, 2020 7:16 PM -
User-474980206 posted
the browser only post backs selected checkboxes and only the name & value of the selected checkbox. to send the barcode, you need to include in a form field, say a hidden field.
you could use the mvc trick of having a hidden field for the checkboxes or just use the helper:
<form asp-action="Assortment" method="post"> @for (var i = 0; i < Model.Checkboxes!.Count; i++) { <div class="[ form-group ]"> <input asp-for="@Model.Checkboxes[i].IsSelected" type="checkbox" /> <div class="[ btn-group ]"> <label asp-for="@Model.Checkboxes[i].IsSelected">@Model.Checkboxes[i].ProductName</label> </div> <input type="hidden" asp-for="Model.Checkboxes[i].ProductName" /> <input type="hidden" asp-for="Model.Checkboxes[i].Barcode" /> <input type="hidden" asp-for="Model.Checkboxes[i].ProductId" /> </div> } <div class="form-group"> <input type="submit" value="Send email" class="btn btn-primary"/> </div> </form>
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, July 2, 2020 7:20 PM
All replies
-
User348806598 posted
Hi Kalev,
Welcome to the community.
Your view is not correct. You need to name your controls in specific ways-
@model MVCSamples.Models.ProductInShopsCheckboxViewModel @{ ViewData["Title"] = "Assortment"; } <h1>Assortment</h1> <form action="_2168657_Getting_back_empty_viewmodel/AssortmentSave" method="post"> @for (var i = 0; i < Model.Checkboxes!.Count; i++) { <script> function changeChecked(checkbox, hiddenId) { document.getElementById(hiddenId).value = checkbox.checked; } </script> <div class="[ form-group ]"> <input name="Checkboxes[@i].ProductId" type="hidden" value="@Model.Checkboxes[@i].ProductId" /> <label> <input checked="@(Model.Checkboxes[@i].IsSelected? "checked" : "")" onchange="changeChecked(this, 'IsSelected_@i')" type="checkbox" /> <input name="Checkboxes[@i].IsSelected" type="hidden" id="IsSelected_@i" value="@Model.Checkboxes[@i].IsSelected" /> @Model.Checkboxes[@i].ProductName </label> <label>Bar code : @Model.Checkboxes[@i].Barcode</label> </div> } <div class="form-group"> <input type="submit" value="Send email" class="btn btn-primary" /> </div> </form>
A working sample is there in this repository-
Thursday, July 2, 2020 7:13 PM -
User348806598 posted
There is a better way of doing this without naming the names of controls yourself. To use helper methods like below-
@model MVCSamples.Models.ProductInShopsCheckboxViewModel @{ ViewData["Title"] = "Assortment"; } <h1>Assortment</h1> <form action="_2168657_Getting_back_empty_viewmodel/AssortmentSave" method="post"> @for (var i = 0; i < Model.Checkboxes!.Count; i++) { <div class="[ form-group ]"> @Html.HiddenFor(model => model.Checkboxes[i].ProductId) <label>@Html.CheckBoxFor(model => model.Checkboxes[i].IsSelected)</label> @Html.DisplayFor(model => model.Checkboxes[i].ProductName) <label>Bar code : @Model.Checkboxes[i].Barcode</label> </div> } <div class="form-group"> <input type="submit" value="Send email" class="btn btn-primary" /> </div> </form>
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, July 2, 2020 7:16 PM -
User-474980206 posted
the browser only post backs selected checkboxes and only the name & value of the selected checkbox. to send the barcode, you need to include in a form field, say a hidden field.
you could use the mvc trick of having a hidden field for the checkboxes or just use the helper:
<form asp-action="Assortment" method="post"> @for (var i = 0; i < Model.Checkboxes!.Count; i++) { <div class="[ form-group ]"> <input asp-for="@Model.Checkboxes[i].IsSelected" type="checkbox" /> <div class="[ btn-group ]"> <label asp-for="@Model.Checkboxes[i].IsSelected">@Model.Checkboxes[i].ProductName</label> </div> <input type="hidden" asp-for="Model.Checkboxes[i].ProductName" /> <input type="hidden" asp-for="Model.Checkboxes[i].Barcode" /> <input type="hidden" asp-for="Model.Checkboxes[i].ProductId" /> </div> } <div class="form-group"> <input type="submit" value="Send email" class="btn btn-primary"/> </div> </form>
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, July 2, 2020 7:20 PM