Reputation: 69
On a page in a Razor MVC app a bunch of lines are written from a model, like this:
@foreach (var item in Model)
{
// write lots of data
@Html.CheckBoxFor(item.Id) // incorrect syntax, I know
}
<input type="button" value="Update" onclick="Update();" />
The javascript that is run from the button is supposed to get the item.Id (which is a unique integer) from each checkbox that has been checked, put the ids in an array and pass the array to another function. This is what I'm working with so far:
function Update() {
var ids = document.getElementsByName("myCheckbox");
var idList = new Array(ids.length);
for (var i = 0; i < ids.length; i++) {
if (ids[i].checked {
idList.push(ids[i]);
}
}
$.ajax({
type: "POST",
url: "@Url.Action("Update", "Home")",
data: idList,
success: function (data) {
},
error: function (data) {
console.log(data);
}
});
}
How do I add the same name to all the checkboxes and have their ID be that of item.Id?
Edit
I tried C Murphy's suggestion by making a class for the checkboxes:
public class ToBeUpdated
{
public int ID { get; set; }
public bool IsSelected { get; set; }
}
And then adding a List to the class that's in the model:
public List<ToBeUpdated> ToBeUpdatedList { get; set; }
However, I can't figure out how to write the CheckBoxFor. His/her suggestion was:
@Html.CheckboxFor(modelItem => modelItem.SomeNameList[i].IsSelected)
But I'm not doing a for loop but a foreach:
foreach (var item in Model)
So I had to do this instead:
@Html.CheckBoxFor(modelItem => item.ToBeUpdatedList.Find(m => m.ID == item.Id).IsSelected)
Then I have my button that sends me to the function in my controller:
<input type="button" value="Update" onclick="location.href='@Url.Action("UpdateStatuses", "Home")'" />
public IActionResult UpdateStatuses(IEnumerable<FileData> model)
{
// iterate through the items in the model
}
The problem is that when I get to UpdateStatuses the model is empty even though I had a ton of checkboxes that I checked before clicking the button. The model in the View is
@model IEnumerable<MyData>
And MyData is a simple class:
public class MyData
{
public int Id { get; set; }
public List<ToBeUpdated> ToBeUpdatedList { get; set; }
}
Edit 2: Finally found a solution
I made my checkboxes like this:
<input type="checkbox" name="chkUpdateThis" id="@item.Id" />
And then I could, with the help of T.J's code, edit my javascript to do this:
function UpdateStatuses() {
const ids = [...document.querySelectorAll("[name=chkUpdateThis]")].filter(({checked}) => checked).map(({id}) => id)
var idList = new Array();
for (var i = 0; i < ids.length; i++) {
idList.push(parseInt(ids[i]));
}
$.ajax({
type: "POST",
url: "@Url.Action("UpdateStatuses", "Home")",
data: ({ ids: idList }),
success: function (data) {
},
error: function (data) {
console.log(data);
}
});
}
Then I can call the UpdateStatuses function in my Home controller:
public IActionResult UpdateStatuses(List<int> ids)
Since T.J didn't post a suggestion that I can give a checkbox to, I'll give it to C Murphy who was also helpful. I didn't use his suggestion, but I don't want to give myself a checkbox even though the solution I went for is right here.
Upvotes: 1
Views: 1389
Reputation: 57
On a similar note to what Heretic Monkey commented, you should probably set up a class. Without knowing what your Update ActionResult is doing in your controller, I can't give you a complete answer, but you could follow this general structure:
Model:
public class SomeNameViewModel
{
public List<SomeName> SomeNameList { get; set; }
}
public class SomeName
{
public int Id { get; set; }
public bool IsSelected { get; set; }
}
View:
@model ProjectName.Models.SomeNameViewModel
@for (var i = 0; i < Model.Count(); i++)
{
<table>
<tr>
<td>@Html.HiddenFor(modelItem => modelItem.SomeNameList[i].Id)</td>
<td>@Html.CheckboxFor(modelItem => modelItem.SomeNameList[i].IsSelected)</td>
</tr>
</table>
}
Edit (due to information provided via comment):
(note I also adjusted the previous section to use a ViewModel instead of a list of the new class)
You would then adjust your ActionResult to instead accept the ViewModel class as an argument and perform the database update as follows:
Controller:
public ActionResult Update(SomeNameViewModel viewModel)
{
List<int> selectedIds = new List<int>();
foreach(var row in viewModel.SomeNameList)
{
if(row.IsSelected == true)
{
selectedIds.Add(row.Id);
}
else
{
// wasn't selected, so do nothing
}
}
// Now you have a list of Ids (selectedIds) that were selected
// and can then be passed to your other function
}
Second Edit:
I think there is still some confusion surrounding the business requirement around what you are trying to accomplish.
The reason for the error was I assumed you would be passing those IDs (in the form of the ToBeUpdated
view model class) to the ActionResult
, instead of passing in the IEnumerable<FileData>
. That is why it is empty when it reaches your controller. The structure of MVC (Model View Controller) dictates that you pass information in the form of a model (class) to the controller from the view (and vice versa).
Please provide your full model list along with a more detailed explanation of what you are trying to achieve and why.
The reason why I utilized a for loop instead of a foreach loop is to ensure that the list is serialized with unique indexes for each item in the list. The only reason you need to use checkboxes is to identify which IDs are to be updated. The logic to determine which are going to be updated should be used on the controller side. Think of a checkbox as an input field for a boolean (true/false, 0/1) property. The goal of a unique ID is just to identify your unique data records. The boolean (checkbox field on the view side) is just to have your end user designate a specific record(s) as needing to be updated.Whatever your model may be, you should add a boolean property (like I gave as an example) to have the user determine which record(s) to update, and call the SQL update command from your controller ONLY on the records from your list/IEnumerable that have a value of true for your IsSelected property.
Upvotes: 1
Reputation: 14389
@Html.CheckBoxFor(model => model.Id, new { Name = "myCheckbox" })
Upvotes: 2