When I get the View with the same model, it contains 2 questions with 2 answeroptions for each question. So far so good.
The problem is that no matter what answer-options I select I always get zero questions back when I post the form even though my indices look right when I inspect the produced HTML, the texts are rendered properly so the loop and indices should work. I have used asp-for on inputs to bind the properties. Why don't I get any questions back?
I have searched for similar posts but I simply cannot see what I am doing different or wrong, so I must be missing something. Please help!
This is the View to reproduce the issue:
@model JobMediation.Api.Models.Onboarding.ViewModels.StartOnboardingOnlineTestModel
@{
ViewData["Title"] = "Online-test!";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm("StartOnboardingOnlineTest", "Onboarding", Model, FormMethod.Post))
{
<div>
@for (var i = 0; i < Model.OnboardingTestQuestions.Count; i++)
{
<p>
@(i + 1). @Model.OnboardingTestQuestions[i].QuestionText
</p>
@for (var j = 0; j < Model.OnboardingTestQuestions[i].OnboardingTestAnswerOptions.Count; j++)
{
<div>
<input type="radio" asp-for="@Model.OnboardingTestQuestions[i].SelectedAnswerOptionId" value="@Model.OnboardingTestQuestions[i].OnboardingTestAnswerOptions[j].AnswerOptionId">
<label><p>@(j + 1). @Model.OnboardingTestQuestions[i].OnboardingTestAnswerOptions[j].Text</p></label>
</div>
}
<div style="display:none">
questionId: <input hidden asp-for="@Model.OnboardingTestQuestions[i].QuestionId" type="text" required>
questionText: <input hidden asp-for="@Model.OnboardingTestQuestions[i].QuestionText" type="text" required>
</div>
}
<button>Send</button>
</div>
}
My ViewModel:
using System.Collections.Generic;
namespace JobMediation.Api.Models.Onboarding.ViewModels
{
public class StartOnboardingOnlineTestModel
{
public List<OnboardingTestQuestion> OnboardingTestQuestions { get; set; } = new List<OnboardingTestQuestion>();
}
}
using System.Collections.Generic;
namespace JobMediation.Api.Models.Onboarding.ViewModels
{
public class OnboardingTestQuestion
{
public string QuestionId{ get; set; }
public string QuestionText { get; set; }
public List<OnboardingTestAnswerOption> OnboardingTestAnswerOptions { get; set; } = new List<OnboardingTestAnswerOption>();
public string SelectedAnswerOptionId { get; set; }
}
}
namespace JobMediation.Api.Models.Onboarding.ViewModels
{
public class OnboardingTestAnswerOption
{
public string AnswerOptionId { get; set; }
public string Text { get; set; }
}
}
My Controller:
[HttpGet]
[Route("/route")]
[CanBeLoggedInAttribute]
public async Task<IActionResult> StartOnboardingOnlineTest()
{
var model = new StartOnboardingOnlineTestModel
{
OnboardingTestQuestions = new List<OnboardingTestQuestion> {
new Models.Onboarding.ViewModels.OnboardingTestQuestion
{
QuestionId = Guid.NewGuid().ToString(),
QuestionText = "Question 1",
OnboardingTestAnswerOptions = new List<OnboardingTestAnswerOption>
{
new Models.Onboarding.ViewModels.OnboardingTestAnswerOption
{
AnswerOptionId = Guid.NewGuid().ToString(),
Text = "Option 1"
},
new Models.Onboarding.ViewModels.OnboardingTestAnswerOption
{
AnswerOptionId = Guid.NewGuid().ToString(),
Text = "Option 2"
}
},
SelectedAnswerOptionId = Guid.Empty.ToString()
},
new Models.Onboarding.ViewModels.OnboardingTestQuestion
{
QuestionId = Guid.NewGuid().ToString(),
QuestionText = "Question 2",
OnboardingTestAnswerOptions = new List<OnboardingTestAnswerOption>
{
new Models.Onboarding.ViewModels.OnboardingTestAnswerOption
{
AnswerOptionId = Guid.NewGuid().ToString(),
Text = "Option A"
},
new Models.Onboarding.ViewModels.OnboardingTestAnswerOption
{
AnswerOptionId = Guid.NewGuid().ToString(),
Text = "Option B"
}
},
SelectedAnswerOptionId = Guid.Empty.ToString()
}
}
};
return View("TEMP", model);
}
[HttpPost]
[Route("/route")]
public async Task<IActionResult> StartOnboardingOnlineTest(StartOnboardingOnlineTestModel model)
{
// Handle the returned questions, but when debugging the model-parameter returns an empty list as model.OnboardingTestQuestions, see picture below
}
Picture of the returned empty list of OnboardingTestQuestions, from debug:
I have googled for similar posts but I already implemented according to them as far as I can see. I use for-loops instead of foreach and the indices look correct, I use asp-for and HTML-inputs to get the data in return but without success.
E.g. I checked this post, Why does my bound List<T> return empty using foreach loop to display values on razor page?, among many others, which I think I have done the same as, but my code still doesn't work. I have also tried with and without [BindProperty] on the OnboardingTestQuestions-list and [BindProperties] on the StartOnboardingOnlineTestModel-class, without any difference. I have also tried with and without the list-instantiations in OnboardingTestQuestions-list and the OnboardingTestAnswerOption.-list, also with the same result.
GET works perfectly. The View looks as expected. The indices of Questions and answeroptions work as I view them in the view and I have also inspected the produced HTML by right clicking and choosing inspect - but apparently something is not working still. Below is the form-HTML produced:
<form action="/soot?OnboardingTestQuestions=JobMediation.Api.Models.Onboarding.ViewModels.OnboardingTestQuestion&OnboardingTestQuestions=JobMediation.Api.Models.Onboarding.ViewModels.OnboardingTestQuestion" method="post"> <div>
<p>
1. Question 1
</p>
<div>
<input type="radio" value="1dd8ff8d-fcaa-4a7d-b10f-e7c41bdd8c11" id="OnboardingTestQuestions_0__SelectedAnswerOptionId" name="OnboardingTestQuestions[0].SelectedAnswerOptionId">
<label><p>1. Option 1</p></label>
</div>
<div>
<input type="radio" value="37c6c1d3-40af-4fc0-a171-4546413c59f0" id="OnboardingTestQuestions_0__SelectedAnswerOptionId" name="OnboardingTestQuestions[0].SelectedAnswerOptionId">
<label><p>2. Option 2</p></label>
</div>
<div style="display:none">
<br>questionId: <input hidden="" type="text" required="" id="OnboardingTestQuestions_0__QuestionId" name="OnboardingTestQuestions[0].QuestionId" value="c90d42ff-a67e-42e2-9ef1-e61ad64f783f">
<br>questionText: <input hidden="" type="text" required="" id="OnboardingTestQuestions_0__QuestionText" name="OnboardingTestQuestions[0].QuestionText" value="Question 1">
</div>
<p>
2. Question 2
</p>
<div>
<input type="radio" value="a9021d17-86d5-4d08-a36a-eeb88661a756" id="OnboardingTestQuestions_1__SelectedAnswerOptionId" name="OnboardingTestQuestions[1].SelectedAnswerOptionId">
<label><p>1. Option A</p></label>
</div>
<div>
<input type="radio" value="9ed4e62c-2a7c-42d8-a2b6-6e97d2d07806" id="OnboardingTestQuestions_1__SelectedAnswerOptionId" name="OnboardingTestQuestions[1].SelectedAnswerOptionId">
<label><p>2. Option B</p></label>
</div>
<div style="display:none">
<br>questionId: <input hidden="" type="text" required="" id="OnboardingTestQuestions_1__QuestionId" name="OnboardingTestQuestions[1].QuestionId" value="0b420127-bfde-4a77-b109-683c4395da27">
<br>questionText: <input hidden="" type="text" required="" id="OnboardingTestQuestions_1__QuestionText" name="OnboardingTestQuestions[1].QuestionText" value="Question 2">
</div>
<button>Send</button>
</div>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8AnsrMzqwIVDvpNxYQXCuLVEqQaff31nYTXBVOW9EkiqYNmFWZHDGA2PfVBLPbbw_FTkHwn5ZsC7zmr1s8lYvxiXRwcCyVTOY4Lq2rbMfasFP4K_5XXEvY2TlqOOGFDUwpj1GHU1X7ZmRIDqHEh3UvU"></form>
POST gets no questions back. Why? What am I missing? Please help!
Using below code can fix the issue, here is the test result.
@model JobMediation.Models.StartOnboardingOnlineTestModel
@{
ViewData["Title"] = "Online-test!";
}
@using (Html.BeginForm("StartOnboardingOnlineTest", "Onboarding", FormMethod.Post))
{
<div>
@for (var i = 0; i < Model.OnboardingTestQuestions.Count; i++)
{
<p>@(i + 1). @Model.OnboardingTestQuestions[i].QuestionText</p>
@for (var j = 0; j < Model.OnboardingTestQuestions[i].OnboardingTestAnswerOptions.Count; j++)
{
<div>
<input type="radio" asp-for="@Model.OnboardingTestQuestions[i].SelectedAnswerOptionId" value="@Model.OnboardingTestQuestions[i].OnboardingTestAnswerOptions[j].AnswerOptionId" />
<label>@(j + 1). @Model.OnboardingTestQuestions[i].OnboardingTestAnswerOptions[j].Text</label>
</div>
}
<div style="display:none">
<input hidden asp-for="@Model.OnboardingTestQuestions[i].QuestionId" type="text" required />
<input hidden asp-for="@Model.OnboardingTestQuestions[i].QuestionText" type="text" required />
</div>
}
<button>Send</button>
</div>
}