I have a .NET 7 MVC application, that has a dynamically generated list of groups with a checkbox, 2 read-only fields, and one numeric field. One of those fields causes the entire model not to be passed to controller method. I checked that by commenting out specific fields one by one until I found the one, which is @Model.SelectedCheckboxViewModel[i].Grams.
Now. I've checked data types, setting up brand new field (that is not used in any other places but here), clearing model state, modifying data types (such as using default value for the field, making it nullable, marking as required and data annotating for never validating). None of the above helped the issue, as long as I've got numeric field in the form, viewModel is not passed along to post method in controller. The passing works neither with Create nor with Edit.
If anyone had any advice I would appreciate it very much. It drives me nuts.
ViewModel that should be passed:
public class RecipeViewModel : BaseViewModel
{
public RecipeDTO Recipe { get; set; } = new RecipeDTO();
public List<RecipeDTO> Recipes { get; set; } = new List<RecipeDTO>();
public List<SelectedCheckboxViewModel> SelectedCheckboxes { get; set; }
public IEnumerable<Category> Categories { get; set; }
public bool IsIngredientBeingSwitched { get; set; } = false;
}
public class SelectedCheckboxViewModel
{
public int? Id { get; set; }
public bool IsChecked { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public int Grams { get; set; }
public double Amount { get; set; }
public Product Product { get; set; } = new Product();
public string ProductId { get; set; }
public int TotalKcal {get; set;}
public double GL {get; set;}
}
Controller method:
[HttpPost]
public IActionResult Edit(RecipeViewModel model)
{
//model here is always null
if ( model == null)
{
return RedirectToAction("Index");
}
}
View:
@model RecipeViewModel
@{
var url = Model.Recipe.Id == 0 ? Url.Action("Create", "Recipe") : Url.Action("Edit", "Recipe");
url = Model.IsIngredientBeingSwitched && Model.Recipe.Id != 0 ? Url.Action("ChangeIngredients", "Recipe") : url;
}
<div class="container">
<form method="post" action="@url">
<div class="mb-3 row">
<label asp-for="@Model.Recipe.TotalKcal"></label>
<input id="totalRecipe" asp-for="@Model.Recipe.TotalKcal" class="form-control" readonly/>
<label asp-for="@Model.Recipe.TotalGL"></label>
<input id="totalRecipeGL" asp-for="@Model.Recipe.TotalGL" class="form-control" readonly />
</div>
<div class="mb-3 row">
<input hidden asp-for="@Model.Recipe.Id" />
<input hidden asp-for="@Model.Recipe.MealId" />
<input hidden asp-for="@Model.Recipe.RecipeDayId" />
<label asp-for="@Model.Recipe.Name"></label>
<input asp-for="@Model.Recipe.Name" class="form-control" />
</div>
@foreach( Category category in Model.Categories)
{
<text>
<div class="m-2"><h3>@category.Name</h3></div>
<div class="row">
@for (var i = 0; i < Model.SelectedCheckboxes.Count(); i++)
{
if (Model.SelectedCheckboxes[i].CategoryId == category.Id)
{
<text>
<div class="col-auto">
<div>
<input class="form-number-input" asp-for="@Model.SelectedCheckboxes[i].IsChecked" type="checkbox">
<input hidden asp-for="@Model.SelectedCheckboxes[i].Id" />
<label class="form-check-label" asp-for="@Model.SelectedCheckboxes[i].IsChecked">@Model.SelectedCheckboxes[i].Name</label>
</div>
<div >
<div>
<label class="form-check-label" asp-for="@Model.SelectedCheckboxes[i].Grams">Amount: </label>
<!-- Removing this bad boy solves the issue. However I need this value, too. -->
<input class="form-control-sm" asp-for="@Model.SelectedCheckboxes[i].Grams"/>
</div>
<div>
<label class="form-check-label" asp-for="@Model.SelectedCheckboxes[i].TotalKcal">Selected kcals: </label>
<input class="form-control-sm total-kcal" asp-for="@Model.SelectedCheckboxes[i].TotalKcal" readonly>
</div>
<div>
<label class="form-check-label" asp-for="@Model.SelectedCheckboxes[i].GL">Load: </label>
<input class="form-control-sm total-gl" asp-for="@Model.SelectedCheckboxes[i].GL" readonly>
</div>
</div>
</div>
</text>
}
}
</div>
</text>
}
<button type="submit" class="btn btn-primary mt-5">Save</button>
</form>
</div>
Below is my Edit test code, you can try it with the code you provided or create a new project to try it:
public IActionResult Edit()
{
var r1 = new RecipeDTO() { Id=1, TotalKcal ="AA", TotalGL ="GG", RecipeDayId =1,MealId=1,Name="QQ"};
var c1 = new List<Category>() { new Category() {Id=1,Name="AA" }, new Category() { Id = 2, Name = "BB" } };
var s1 = new List<SelectedCheckboxViewModel>() { new SelectedCheckboxViewModel() { CategoryId=1,Id=1,IsChecked=true,Name="AA",Grams=1,TotalKcal=1,GL=1.0} };
var model = new RecipeViewModel() { Recipe=r1,Categories=c1,SelectedCheckboxes=s1 };
return View(model);
}