This is my first question here at stackoverflow. Hehehe.
I have an edit page which I need to display all the existing fields and I have an add button which I can add a new field.
Here is the source code for edit in which where the displaying of data happens (Edit.cshtml)
<div >
@for (int i = 0; i < Model.NutritionFacts.Count(); i )
{
<div >
<div >
<label>Nutrients name</label>
<input type="text" asp-for="@Model.NutritionFacts.ToList()[i].NutritionName">
<span asp-validation-for="@Model.NutritionFacts.ToList()[i].NutritionName" ></span>
</div>
<div >
<label>Per 100g</label>
<input type="text" asp-for="@Model.NutritionFacts.ToList()[i].Gram">
<span asp-validation-for="@Model.NutritionFacts.ToList()[i].Gram" ></span>
</div>
<div >
<label>% Daily value</label>
<div >
<input type="text" asp-for="@Model.NutritionFacts.ToList()[i].PercentageDailyValue">
<span asp-validation-for="@Model.NutritionFacts.ToList()[i].PercentageDailyValue" ></span>
<a href="javascript:void(0)" >
Delete
</a>
</div>
</div>
</div>
}
</div>
And here is the javascript for the add button:
$(addNutrition).click(function() {
$.ajax({
url: "/Product/AddNutrition",
cache: false,
success: function (html) {
$('.nutrition-field').append(html)
}
});
});
When you click the button it will go to the controller and here is the code for the Add Nutrition Controller:
public IActionResult AddNutrition()
{
return PartialView("~/Views/Product/PartialViews/_AddNutrition.cshtml", new ProductNutritionFactsDto());
}
Here is the Partial View:
@model ProjectName.Dto.ProductNutritionFactsDto
<div >
<div >
<label>Nutrients name</label>
<input type="text" asp-for="NutritionName">
<span asp-validation-for="NutritionName" ></span>
</div>
<div >
<label>Per 100g</label>
<input type="text" asp-for="Gram">
<span asp-validation-for="Gram" ></span>
</div>
<div >
<label>% Daily value</label>
<div >
<input type="text" asp-for="PercentageDailyValue">
<span asp-validation-for="PercentageDailyValue" ></span>
<a href="javascript:void(0)" >
Delete
</a>
</div>
</div>
</div>
It's working but I wanted it to be inside the for loop so the counting of index will continue and it will have a unique ID. What is happening is it is creating a new model and the validations are not working when adding many fields.
I would really appreciate your help everyone. Thank you!
CodePudding user response:
I saw you use @Model.NutritionFacts.ToList()[i].PropertyName
in main view and ProductNutritionFactsDto
in partial view. Assume that your main view accept a model contains nested List<ChildModel>
called ProductNutritionFactsDto
.
For your scenario, you need pass the count to ajax and use ViewBag to store the count and use it in the partial view:
Main View:
model TestViewModel
<button id="addNutrition" type="button">Add</button>
<form method="post">
<div >
@for (int i = 0; i < Model.NutritionFacts.Count(); i )
{
<div >
<div >
<label>Nutrients name</label>
<input type="text" asp-for="@Model.NutritionFacts.ToList()[i].NutritionName">
<span asp-validation-for="@Model.NutritionFacts.ToList()[i].NutritionName" ></span>
</div>
<div >
<label>Per 100g</label>
<input type="text" asp-for="@Model.NutritionFacts.ToList()[i].Gram">
<span asp-validation-for="@Model.NutritionFacts.ToList()[i].Gram" ></span>
</div>
<div >
<label>% Daily value</label>
<div >
<input type="text" asp-for="@Model.NutritionFacts.ToList()[i].PercentageDailyValue">
<span asp-validation-for="@Model.NutritionFacts.ToList()[i].PercentageDailyValue" ></span>
<a href="javascript:void(0)" >
Delete
</a>
</div>
</div>
</div>
}
</div>
<input type="submit" value="post" />
</form>
@section Scripts
{
<script>
$("#addNutrition").click(function () {
$.ajax({
url: "/Product/AddNutrition?index=" $(".nutrients-name").length,
cache: false,
success: function (html) {
$('.nutrition-field').append(html)
}
});
});
</script>
}
Controller:
public IActionResult AddNutrition(int index)
{
ViewBag.Index = index;
return PartialView("~/Views/Product/PartialViews/_AddNutrition.cshtml", new ProductNutritionFactsDto());
}
Partial View:
Get the ViewBag.Index
and add name attribute with this index.
@model ProductNutritionFactsDto
@{
var i = (int)ViewBag.Index;
}
<div >
<div >
<label>Nutrients name</label>
<input type="text" asp-for="NutritionName" name="[@i].NutritionName">
<span asp-validation-for="NutritionName" ></span>
</div>
<div >
<label>Per 100g</label>
<input type="text" asp-for="Gram" name="[@i].Gram">
<span asp-validation-for="Gram" ></span>
</div>
<div >
<label>% Daily value</label>
<div >
<input type="text" asp-for="PercentageDailyValue" name="[@i].PercentageDailyValue">
<span asp-validation-for="PercentageDailyValue" ></span>
<a href="javascript:void(0)" >
Delete
</a>
</div>
</div>
</div>
Testing model:
public class TestViewModel
{
public List<ProductNutritionFactsDto> NutritionFacts { get; set; }
}
public class ProductNutritionFactsDto
{
[Required]
public string NutritionName { get; set; }
public string Gram { get; set; }
public string PercentageDailyValue { get; set; }
}
Besides, notes for further coding(about posting the data to backend):
asp-for="@Model.NutritionFacts.ToList()[i].PropertyName"
will generate the name attribute: name="[i].PropertyName"
, so if you want to post all the ProductNutritionFactsDto
models in the page, be sure the backend parameter should be List<ProductNutritionFactsDto>
.
[HttpPost]
public void Index(List<ProductNutritionFactsDto> model)
{
if(ModelState.IsValid)
{
//....
}
//.....
}
If you just want to pass any one ProductNutritionFactsDto
model in the page separately, be sure add name attribute(name="PropertyName"
) to override the asp-for
generated name and the backend parameter should be ProductNutritionFactsDto
.
CodePudding user response:
The first form group is the one in for loop, before adding a new field so the validation is working when clicking the submit button. The second form group is the one after clicking the add button.
How can I use the asp-validation-for? I tried this one but it's not working.
<span asp-validation-for="[@i].NutritionName" ></span>