so I have been tasked with creating a questionnaire that pulls the information from a table in a database, displays the relevant information, accepts inputs, and posts inputted information to a separate table.
In the interest of further learning MVC I am using that to create this, so forgive me if I have made crucial errors. I have read a decent few posts and many are similar but do not quite address the same situation (most go over multiple models on a page but not a list of models)
My issue at present is that the list of models passed to the view does not seem to be posted back when the HttpPost is called on submit. I have only worked with posting single models before this point, and am unsure if this is even possible. If not that is fine, but some direction on what the best practice approach to handling this would be appreciated.
Below is the controller code, the Question(List list) is where the issue occurs as the list returned is just NULL.
public ActionResult Question() // load the questionnaire
{
List<QuestionModel> list = new List<QuestionModel>();
var data = GetQuestionnaire();
foreach (var row in data) // convert the data into the current question model.
{
list.Add(new QuestionModel
{
questionnaire_id = row.questionnaire_id,
question_text = row.question_text,
category_id = row.category_id,
category_name = row.category_name,
type_format = row.type_format,
response = row.response
});
}
ViewBag.Message = "Questionnaire page.";
return View(list);
}
[HttpPost]
public ActionResult Question(List<QuestionModel> list) // load responses and push to backend to store in database.
{
return View(list);
}
And bellow is the entire .cshtml page. My current assumption is that I am unable to even edit each individual model on this one page, as well as that the post does not pass the same list of models back.
@model IEnumerable<QuestionnaireWebForm.Models.QuestionModel>
@{bool t1 = false;}
<h2>
Questionnaire
</h2>
@using (Html.BeginForm()) // creates the submit form and houses clinic list retrieved
{
<div >
<div >
<div >
<input type="submit" value="Save Form" />
</div>
</div>
<hr>
@foreach (var item in Model)
{
if (item.type_format == 0 && t1 == false)
{
<h3> @Html.DisplayFor(modelItem => item.category_name)</h3>
@Html.Raw("<div class=\"col-md\"> ")
t1 = true;
}
else if (item.type_format == 0 && t1 == true)
{
@Html.Raw("</div>")
<hr>
<h3> @Html.DisplayFor(modelItem => item.category_name)</h3>
@Html.Raw("<div class=\"col-md\"> ")
}
else
{
@Html.DisplayFor(modelItem => item.question_text)
<br>
@Html.EditorFor(modelItem => item.response)
<br>
}
}
@Html.Raw("</div>")
<hr>
<div >
<div >
<input type="submit" value="Save Form" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to Home", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
The page as it currently displays. This is as I desired it to look overall, so this has worked well (seeing as accordions would not collapse or expand despite a few different attempts to repair those).
Would it be best to attempt to create a model that stores a variable number of headers/questions and then display as one model? or takes all the models and store them as individual arrays of some sort and then pass a list of arrays back and forth?
If any further information is required let me know. (I will be redesigning this as a workable form at this time but will be keeping the current form as a test.)
CodePudding user response:
It should work if you replace IEnumeable with List and use Model in EditorFor(x => Model[index].category_name)
Possible dublicate: Passing list and a model instance via HTML BeginForm
@using (Html.BeginForm()
{
@for (int idx = 0; idx < Model.Count; idx ) {
@Html.EditorFor(x => Model[index].category_name)
}
}
CodePudding user response:
The data being submitted is not the entire content of your QuestionModel
, it's just the input fields from the form. Modify your public ActionResult Question(List<QuestionModel> list)
to be public ActionResult Question(IFormCollection collection)
so you can see the data that the controller is getting.
There are a few ways you can handle this. One approach is to retrieve the question list again, associate the answers you've received with the relevant question then save that. Something like:
[HttpPost]
public ActionResult Question(IFormCollection collection) // load responses and push to backend to store in database.
{
List<QuestionModel> list = new List<QuestionModel>();
var data = GetQuestionnaire();
for (int i = 0; i < data.Count(); i ) // convert the data into the current question model.
{
list.Add(new QuestionModel
{
questionnaire_id = row.questionnaire_id,
question_text = row.question_text,
category_id = row.category_id,
category_name = row.category_name,
type_format = row.type_format,
response = collection[i].Value // grab the response from the form data
});
}
return View(list);
}