Home > Mobile >  Controller doesn't receive all properties back from the form
Controller doesn't receive all properties back from the form

Time:05-31

I have a class QuestionnaireDetailsViewModel who contains some properties and also a list.

The list could contains from 0 to many items. I send the class QuestionnaireDetailsViewModel to my View in order to display it in a form. For the list part, I use a foreach to render it and it works just fine.

The problem is, all those properties are inputs and when I submit the form, my List is always empty when it's reaching the Controller.

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.

I don't understand how could I make match List properties name with each input of my form since they need to have a unique name. Is it possible to achieve this or should I save each list item separately with a JS loop?

Could you please enlighten me?

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; }
}

View

<form method="post" enctype="multipart/form-data"  id="formFull">
    <div >
        <label  for="Name">Name<span >*</span></label>
        <input asp-for="Name"  type="text" id="Name" required />
        <span asp-validation-for="Name"></span>
        <input asp-for="Id" type="hidden" id="Id" required />
    </div>
    <div  id="accordionExample">
        @foreach (var obj in Model.VenueItems)
        {
            <div >
                <h2  id="[email protected]">
                    <button  type="button" data-bs-toggle="collapse" data-bs-target="#[email protected]" aria-expanded="true" aria-controls="[email protected]" style="margin-top: 0px">
                        @obj.VenueName
                    </button>
                </h2>
                <div id="[email protected]"  aria-labelledby="[email protected]" data-bs-parent="#accordionExample">
                    <div >
                        <div >
                            <label >Did the venue have a sustainable approach?<span >*</span></label>
                            <div >
                                <div >
                                    <input asp-for="@obj.IsEventHaveSustainableApproach"  type="radio" value="1" id="[email protected]" />
                                    <label for="[email protected]">Yes</label>
                                </div>
                                <div >
                                    <input asp-for="@obj.IsEventHaveSustainableApproach"  type="radio" value="0" id="[email protected]" />
                                    <label for="[email protected]">No</label>
                                </div>
                            </div>
                        </div>
                        <div >
                            <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 method to send the form

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;
        });
}

Controller who receive the form back with the property Name filled but list items are empty

public async Task<IActionResult> SaveAsync(QuestionnaireDetailsViewModel questionnaireViewModel)
{
}

CodePudding user response:

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

Yes, it is caused by the same name. For your nested list model, it binds the property by name="[index].PropertyName" or name="VenueItems[index].PropertyName".

Change your frontend code like below:

@model QuestionnaireDetailsViewModel
<form method="post" enctype="multipart/form-data"  id="formFull">
    <div >
        <label  for="Name">Name<span >*</span></label>
        <input asp-for="Name"  type="text" id="Name" required />
        <span asp-validation-for="Name"></span>
        <input asp-for="Id" type="hidden" id="Id" required />
    </div>
    <div  id="accordionExample">
        @{
            int i = 0;         //add index here........
        }
        @foreach (var obj in Model.VenueItems)
        {
            <div >
                <h2  id="[email protected]">
                    <button  type="button" data-bs-toggle="collapse" data-bs-target="#[email protected]" aria-expanded="true" aria-controls="[email protected]" style="margin-top: 0px">
                        @obj.VenueName
                    </button>
                </h2>
                <div id="[email protected]"  aria-labelledby="[email protected]" data-bs-parent="#accordionExample">
                    <div >
                        <div >
                            <label >Did the venue have a sustainable approach?<span >*</span></label>
                            <div >
                                <div >
                                                       @*add name attribute*@
                                    <input name="VenueItems[@i].IsEventHaveSustainableApproach" asp-for="@obj.IsEventHaveSustainableApproach"  type="radio" value="1" id="[email protected]" />
                                    <label for="[email protected]">Yes</label>
                                </div>
                                <div >
                                    <input name="VenueItems[@i].IsEventHaveSustainableApproach" asp-for="@obj.IsEventHaveSustainableApproach"  type="radio" value="0" id="[email protected]" />
                                    <label for="[email protected]">No</label>
                                </div>
                            </div>
                        </div>
                        <div >
                            <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>
}

Result:

enter image description here

  • Related