Radio Buttons in Editor Template

3.6k views Asked by At

I am in the process of creating a 'Progress Report' with a list of questions and multiple choice answers. The questions are populated into the Progress Report automatically via a separate unrelated process in case it is relevant.

Code is as follows: Edit View:

@model App.Models.ProgressReport
@Html.EditorFor(model => model.ReportAnswers)

ReportAnswer.cshtml EditorTemplate (which shows the question and the answer from the Progress Report):

@model App.Models.ReportAnswer    
<h3>
    Question
</h3>

<p>
    @Html.DisplayFor(x => x.Question.QuestionText)
</p>
<p>
    @Html.EditorFor(x => x.Question.PossibleAnswers)
</p>
<p>
    @Html.LabelFor(x => x.AnswerID)
    @Html.TextBoxFor(x => x.AnswerID)
</p>

PossibleAnswer.cshtml (Editor Template which shows all available answers to the question):

@model App.Models.PossibleAnswer

<p>
    @Html.DisplayFor(x => x.AnswerText)
    @Html.RadioButtonFor(x => x.AnswerText, Model.AnswerID,  new { Name =Model.QuestionID })
</p>

So this displays all associated questions from the Progress Report and the optional answers.

My problems:

1.) Is that each radio button has a different name which allows me to select all answers for a single question instead of unselecting one as the next is selected.

2.) The selected answer should load as selected the next time I edit the progress report. How to have one of the answers pre-selected on load based on the answer provided the last time the view was loaded.

3.) How to return the selected answer back to the Edit action in my ProgressReport Controller?

Thanks a bunch for any assistance

EditController Code:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include =  "ReportID,ClientID,ReportDateSubmitted,ReportWeek")] ProgressReport progressReport)
    {
        if (ModelState.IsValid)
        {
            db.Entry(progressReport).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        ViewBag.ClientID = new SelectList(db.Clients, "ClientID", "ID", progressReport.ClientID);
        return View(progressReport);
    }
1

There are 1 answers

9
AudioBubble On BEST ANSWER

Your problem is the use of an EditorTemplate for typeof PossibleAnswer. The EditorFor() method is designed to work with collections and add an prefixes and indexers to the property same so that it can be bound to a collection by the DefaultModelBinder on post back. The second issue is that your binding the radio buttons to property AnswerText of PossibleAnswer, when you should be binding to AnswerID property of ReportAnswer.

Delete the PossibleAnswer.cshtml file and modify the ReportAnswer.cshtml to

@model App.Models.ReportAnswer    
<h3>Question</h3>
<p>@Html.DisplayFor(x => x.Question.QuestionText)</p>
@foreach(var answer in Model.Question.PossibleAnswers)
{
  var id = string.Format("answer-{0}", answer.AnswerID);
  <p>
    @Html.RadioButtonFor(m => m.AnswerID, answer.AnswerID, new { id = id })
    <label for="@id">@answer.AnswerText</label>    
  </p>
}

This will generate html that looks like

<input type="radio" id="answer-1" name="[0].AnswerID" value="1" />
<label for="answer-1">Answer 1</label>
<input type="radio" id="answer-2" name="[0].AnswerID" value="2" />
<label for="answer-2">Answer 2</label>

Side note: NEVER attempt to override the name attribute (as in your usage of new { Name = Model.QuestionID }. There is no surer way to guarantee model binding will fail :)