控制器没有收到表单返回的所有属性
Controller doesn't receive all properties back from the form
我有一个 class QuestionnaireDetailsViewModel,它包含一些属性和一个列表。
该列表可以包含 0 到多个项目。
我将 class QuestionnaireDetailsViewModel 发送到我的视图,以便在表单中显示它。
对于列表部分,我使用 foreach 来渲染它,它工作得很好。
问题是,所有这些属性都是输入,当我提交表单时,我的列表到达控制器时总是空的。
我还注意到,在调用的有效负载中,它只将列表中的第一项发送到控制器,但我相信这是因为每一项都具有相同的名称。
我不明白如何使列表属性名称与表单的每个输入相匹配,因为它们需要有一个唯一的名称。
是否可以实现此目的,或者我应该使用 JS 循环分别保存每个列表项?
能请教一下吗?
QuestionnaireDetailsViewModel class
public class QuestionnaireDetailsViewModel
{
public string Id { get; set; }
public string Name { get; set; }
public List<VenueViewModel> VenueItems { get; set; }
}
VenueViewModel class
public class VenueViewModel
{
public string Id { get; set; }
public string Id_Que { get; set; }
public string VenueName { get; set; }
public string Checkbox_Other { get; set; }
public string IsEventHaveSustainableApproach { get; set; }
}
查看
<form method="post" enctype="multipart/form-data" class="form-content-column" id="formFull">
<div class="input-box">
<label class="numbered" for="Name">Name<span class="span-mandatory">*</span></label>
<input asp-for="Name" class="input-mandatory" type="text" id="Name" required />
<span asp-validation-for="Name"></span>
<input asp-for="Id" type="hidden" id="Id" required />
</div>
<div class="accordion" id="accordionExample">
@foreach (var obj in Model.VenueItems)
{
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne@obj.Id">
<button class="accordion-button accordion-button-custom" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne_@obj.Id" aria-expanded="true" aria-controls="collapseOne_@obj.Id" style="margin-top: 0px">
@obj.VenueName
</button>
</h2>
<div id="collapseOne_@obj.Id" class="accordion-collapse collapse show" aria-labelledby="headingOne_@obj.Id" data-bs-parent="#accordionExample">
<div class="accordion-body">
<div class="input-box no-border">
<label class="numbered">Did the venue have a sustainable approach?<span class="span-mandatory">*</span></label>
<div class="flex flex-column">
<div class="single-radio">
<input asp-for="@obj.IsEventHaveSustainableApproach" class="input-mandatory radio_Tab1_IsEventHaveSustainableApproach" type="radio" value="1" id="Tab1_IsEventHaveSustainableApproach_Yes_@obj.Id" />
<label for="Tab1_IsEventHaveSustainableApproach_Yes_@obj.Id">Yes</label>
</div>
<div class="single-radio">
<input asp-for="@obj.IsEventHaveSustainableApproach" class="input-mandatory radio_Tab1_IsEventHaveSustainableApproach" type="radio" value="0" id="Tab1_IsEventHaveSustainableApproach_No_@obj.Id" />
<label for="Tab1_IsEventHaveSustainableApproach_No_@obj.Id">No</label>
</div>
</div>
</div>
<div class="input-box">
<label for="Tab1_Checkbox_EventVenue_Other">Other? Please explain</label>
<input asp-for="@obj.Checkbox_Other" type="text" id="Tab1_Checkbox_EventVenue_Other" />
</div>
</div>
</div>
</div>
}
</div>
</form>
js方法发送表单
async function saveForm() {
let formData = new FormData(document.forms[0]);
await fetch('/Reports/Save', {
method: 'post',
body: formData
})
.then((response) => {
toastr.success('Saved successfully');
preventLeaving = false;
return true;
})
.catch((error) => {
toastr.error('An error occured');
return false;
});
}
收到填有 属性 名称但列表项为空的表单的控制器
public async Task<IActionResult> SaveAsync(QuestionnaireDetailsViewModel questionnaireViewModel)
{
}
I also noticed that in the payload of the call, it only send the first item in the list to the controller, but I believe it's because each item have the same name
是的,是同名造成的。对于您的嵌套列表模型,它通过 name="[index].PropertyName"
或 name="VenueItems[index].PropertyName"
.
绑定 属性
像下面这样更改您的前端代码:
@model QuestionnaireDetailsViewModel
<form method="post" enctype="multipart/form-data" class="form-content-column" id="formFull">
<div class="input-box">
<label class="numbered" for="Name">Name<span class="span-mandatory">*</span></label>
<input asp-for="Name" class="input-mandatory" type="text" id="Name" required />
<span asp-validation-for="Name"></span>
<input asp-for="Id" type="hidden" id="Id" required />
</div>
<div class="accordion" id="accordionExample">
@{
int i = 0; //add index here........
}
@foreach (var obj in Model.VenueItems)
{
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne@obj.Id">
<button class="accordion-button accordion-button-custom" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne_@obj.Id" aria-expanded="true" aria-controls="collapseOne_@obj.Id" style="margin-top: 0px">
@obj.VenueName
</button>
</h2>
<div id="collapseOne_@obj.Id" class="accordion-collapse collapse show" aria-labelledby="headingOne_@obj.Id" data-bs-parent="#accordionExample">
<div class="accordion-body">
<div class="input-box no-border">
<label class="numbered">Did the venue have a sustainable approach?<span class="span-mandatory">*</span></label>
<div class="flex flex-column">
<div class="single-radio">
@*add name attribute*@
<input name="VenueItems[@i].IsEventHaveSustainableApproach" asp-for="@obj.IsEventHaveSustainableApproach" class="input-mandatory radio_Tab1_IsEventHaveSustainableApproach" type="radio" value="1" id="Tab1_IsEventHaveSustainableApproach_Yes_@obj.Id" />
<label for="Tab1_IsEventHaveSustainableApproach_Yes_@obj.Id">Yes</label>
</div>
<div class="single-radio">
<input name="VenueItems[@i].IsEventHaveSustainableApproach" asp-for="@obj.IsEventHaveSustainableApproach" class="input-mandatory radio_Tab1_IsEventHaveSustainableApproach" type="radio" value="0" id="Tab1_IsEventHaveSustainableApproach_No_@obj.Id" />
<label for="Tab1_IsEventHaveSustainableApproach_No_@obj.Id">No</label>
</div>
</div>
</div>
<div class="input-box">
<label for="Tab1_Checkbox_EventVenue_Other">Other? Please explain</label>
@*add name attribute*@
<input asp-for="@obj.Checkbox_Other" name="VenueItems[@i].Checkbox_Other" type="text" id="Tab1_Checkbox_EventVenue_Other" />
</div>
</div>
</div>
</div>
i++; //add this.........
}
</div>
</form>
<button type="button" onclick="saveForm()">Post</button>
@section Scripts
{
<script>
async function saveForm() {
let formData = new FormData(document.forms[0]);
await fetch('/Reports/Save', {
method: 'post',
body: formData
})
.then((response) => {
toastr.success('Saved successfully');
preventLeaving = false;
return true;
})
.catch((error) => {
toastr.error('An error occured');
return false;
});
}
</script>
}
结果:
我有一个 class QuestionnaireDetailsViewModel,它包含一些属性和一个列表。
该列表可以包含 0 到多个项目。 我将 class QuestionnaireDetailsViewModel 发送到我的视图,以便在表单中显示它。 对于列表部分,我使用 foreach 来渲染它,它工作得很好。
问题是,所有这些属性都是输入,当我提交表单时,我的列表到达控制器时总是空的。
我还注意到,在调用的有效负载中,它只将列表中的第一项发送到控制器,但我相信这是因为每一项都具有相同的名称。
我不明白如何使列表属性名称与表单的每个输入相匹配,因为它们需要有一个唯一的名称。 是否可以实现此目的,或者我应该使用 JS 循环分别保存每个列表项?
能请教一下吗?
QuestionnaireDetailsViewModel class
public class QuestionnaireDetailsViewModel
{
public string Id { get; set; }
public string Name { get; set; }
public List<VenueViewModel> VenueItems { get; set; }
}
VenueViewModel class
public class VenueViewModel
{
public string Id { get; set; }
public string Id_Que { get; set; }
public string VenueName { get; set; }
public string Checkbox_Other { get; set; }
public string IsEventHaveSustainableApproach { get; set; }
}
查看
<form method="post" enctype="multipart/form-data" class="form-content-column" id="formFull">
<div class="input-box">
<label class="numbered" for="Name">Name<span class="span-mandatory">*</span></label>
<input asp-for="Name" class="input-mandatory" type="text" id="Name" required />
<span asp-validation-for="Name"></span>
<input asp-for="Id" type="hidden" id="Id" required />
</div>
<div class="accordion" id="accordionExample">
@foreach (var obj in Model.VenueItems)
{
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne@obj.Id">
<button class="accordion-button accordion-button-custom" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne_@obj.Id" aria-expanded="true" aria-controls="collapseOne_@obj.Id" style="margin-top: 0px">
@obj.VenueName
</button>
</h2>
<div id="collapseOne_@obj.Id" class="accordion-collapse collapse show" aria-labelledby="headingOne_@obj.Id" data-bs-parent="#accordionExample">
<div class="accordion-body">
<div class="input-box no-border">
<label class="numbered">Did the venue have a sustainable approach?<span class="span-mandatory">*</span></label>
<div class="flex flex-column">
<div class="single-radio">
<input asp-for="@obj.IsEventHaveSustainableApproach" class="input-mandatory radio_Tab1_IsEventHaveSustainableApproach" type="radio" value="1" id="Tab1_IsEventHaveSustainableApproach_Yes_@obj.Id" />
<label for="Tab1_IsEventHaveSustainableApproach_Yes_@obj.Id">Yes</label>
</div>
<div class="single-radio">
<input asp-for="@obj.IsEventHaveSustainableApproach" class="input-mandatory radio_Tab1_IsEventHaveSustainableApproach" type="radio" value="0" id="Tab1_IsEventHaveSustainableApproach_No_@obj.Id" />
<label for="Tab1_IsEventHaveSustainableApproach_No_@obj.Id">No</label>
</div>
</div>
</div>
<div class="input-box">
<label for="Tab1_Checkbox_EventVenue_Other">Other? Please explain</label>
<input asp-for="@obj.Checkbox_Other" type="text" id="Tab1_Checkbox_EventVenue_Other" />
</div>
</div>
</div>
</div>
}
</div>
</form>
js方法发送表单
async function saveForm() {
let formData = new FormData(document.forms[0]);
await fetch('/Reports/Save', {
method: 'post',
body: formData
})
.then((response) => {
toastr.success('Saved successfully');
preventLeaving = false;
return true;
})
.catch((error) => {
toastr.error('An error occured');
return false;
});
}
收到填有 属性 名称但列表项为空的表单的控制器
public async Task<IActionResult> SaveAsync(QuestionnaireDetailsViewModel questionnaireViewModel)
{
}
I also noticed that in the payload of the call, it only send the first item in the list to the controller, but I believe it's because each item have the same name
是的,是同名造成的。对于您的嵌套列表模型,它通过 name="[index].PropertyName"
或 name="VenueItems[index].PropertyName"
.
像下面这样更改您的前端代码:
@model QuestionnaireDetailsViewModel
<form method="post" enctype="multipart/form-data" class="form-content-column" id="formFull">
<div class="input-box">
<label class="numbered" for="Name">Name<span class="span-mandatory">*</span></label>
<input asp-for="Name" class="input-mandatory" type="text" id="Name" required />
<span asp-validation-for="Name"></span>
<input asp-for="Id" type="hidden" id="Id" required />
</div>
<div class="accordion" id="accordionExample">
@{
int i = 0; //add index here........
}
@foreach (var obj in Model.VenueItems)
{
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne@obj.Id">
<button class="accordion-button accordion-button-custom" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne_@obj.Id" aria-expanded="true" aria-controls="collapseOne_@obj.Id" style="margin-top: 0px">
@obj.VenueName
</button>
</h2>
<div id="collapseOne_@obj.Id" class="accordion-collapse collapse show" aria-labelledby="headingOne_@obj.Id" data-bs-parent="#accordionExample">
<div class="accordion-body">
<div class="input-box no-border">
<label class="numbered">Did the venue have a sustainable approach?<span class="span-mandatory">*</span></label>
<div class="flex flex-column">
<div class="single-radio">
@*add name attribute*@
<input name="VenueItems[@i].IsEventHaveSustainableApproach" asp-for="@obj.IsEventHaveSustainableApproach" class="input-mandatory radio_Tab1_IsEventHaveSustainableApproach" type="radio" value="1" id="Tab1_IsEventHaveSustainableApproach_Yes_@obj.Id" />
<label for="Tab1_IsEventHaveSustainableApproach_Yes_@obj.Id">Yes</label>
</div>
<div class="single-radio">
<input name="VenueItems[@i].IsEventHaveSustainableApproach" asp-for="@obj.IsEventHaveSustainableApproach" class="input-mandatory radio_Tab1_IsEventHaveSustainableApproach" type="radio" value="0" id="Tab1_IsEventHaveSustainableApproach_No_@obj.Id" />
<label for="Tab1_IsEventHaveSustainableApproach_No_@obj.Id">No</label>
</div>
</div>
</div>
<div class="input-box">
<label for="Tab1_Checkbox_EventVenue_Other">Other? Please explain</label>
@*add name attribute*@
<input asp-for="@obj.Checkbox_Other" name="VenueItems[@i].Checkbox_Other" type="text" id="Tab1_Checkbox_EventVenue_Other" />
</div>
</div>
</div>
</div>
i++; //add this.........
}
</div>
</form>
<button type="button" onclick="saveForm()">Post</button>
@section Scripts
{
<script>
async function saveForm() {
let formData = new FormData(document.forms[0]);
await fetch('/Reports/Save', {
method: 'post',
body: formData
})
.then((response) => {
toastr.success('Saved successfully');
preventLeaving = false;
return true;
})
.catch((error) => {
toastr.error('An error occured');
return false;
});
}
</script>
}
结果: