0

I have 2 models inside my asp.net mvc-5 web application:-

public partial class Anwer
    {
        public Anwer()
        {
            this.UserFormsAnswers = new HashSet<UserFormsAnswer>();
        }

        public int Id { get; set; }
        public string AnwerDesc { get; set; }
        public int QuestionID { get; set; }
        public bool Correct { get; set; }

        public virtual Question Question { get; set; }
        public virtual ICollection<UserFormsAnswer> UserFormsAnswers { get; set; }
    }

 public partial class Question
    {
        public Question()
        {
            this.Anwers = new HashSet<Anwer>();
        }

        public int Id { get; set; }
        public string QuestionDesc { get; set; }
        public int Order { get; set; }
        public bool Active { get; set; }

        public virtual ICollection<Anwer> Anwers { get; set; }
    }

now i want to show all the questions inside the view and for each question to show its answers in a radio buttons, so i tried the following:-

@model IEnumerable<QuestionsDemo.Models.Question>


@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">

        @{int i = 0;

            foreach (var item in Model)
{
                <div class="form-group">
                    @(i+1) <spn>-</spn> @Html.DisplayFor(modelItem => item.QuestionDesc) <br />
                    @foreach (var answer in item.Anwers)
        {
                        <div class="col-md-10">
                            @Html.RadioButtonFor(modelitem2 => answer.QuestionID, answer.Id) @answer.AnwerDesc  <br /> 
                        </div>
        }
                </div><hr/>
}

        }
    </div>
}

I thought that all the answers' radio buttons for a question will have the same name. so users can only select one option for each question. but seems all the answers radio-buttons got the same name as follow:-

<input id="answer_QuestionID" name="answer.QuestionID" type="radio" value="1" /> 10  <br />

so can any one adivce on this ? how i can group the radio buttons per question?

second question. how i can post back all the answers ids to my post action method? should i use indexer ??

John John
  • 1
  • 72
  • 238
  • 501

1 Answers1

1

You cannot use a foreach loop to generate the form controls for Question. You need to use a for loop, or better a custom EditorTemplate for typeof Question. Refer Post an HTML Table to ADO.NET DataTable for a detailed explanation.

Your Question model also needs a property to bind the selected Answer to, for example

public class Question
{
    public int Id { get; set; }
    ....
    public int SelectedAnswer { get; set; }
}

And note that your editing data so you should be creating view models for both Question and Answer, not using data models in your view.

Create a partial view Views/Shared/EditorTemplates/QuestionVM.cshtml with the following code

@model QuestionsDemo.Models.Question

@Html.HiddenFor(m => m.Id)
// Add additional hidden inputs for any properties of Question that you want to be posted
@Html.DisplayFor(m => m.QuestionDesc)
@foreach(var answer in Model.Anwers)
{
    <label>
        @Html.RadioButtonFor(m => m.SelectedAnswer, answer.Id, new { id = "" })
        <span>@answer.AnwerDesc</span>
    </label>
}

Then the main view will be

@model IEnumerable<QuestionsDemo.Models.Question>
....
@using (Html.BeginForm())
{
    ....
    @Html.EditorFor(m => m)
    <input type="submit" value="Save" />
}

Note the EditorFor() method will correctly generate the html for each item in the collection.

  • now it worked well in respect to the radio buttons and how they are being rendered.. but inside my action method i wrote the following `public async Task Create(List SelectedAnswer)` to capture the selected radio buttons.. Now the SelectedAnswer list will have the correct number of items,, but the value for all the items will be zero instead of having the answerid ?? – John John Jun 09 '17 at 01:40
  • can you adivce on my above comment please? – John John Jun 09 '17 at 01:47
  • 1
    The model in the view is `IEnumerable`, therefore you POST method must match - `public ActionResult XXX (IEnumerable model)` and `model` will contain all the information you have submitted. And having `List SelectedAnswer` would make no sense - it does not contain the data about the question that the answer relates to :) –  Jun 09 '17 at 01:48
  • now i find this problem ,, not sure how i can fix it.. now if the view is rendered after a model state error the view will be empty.. so seems `@Html.EditorFor(m => m)` will not get rendered in-case the view is rendered again due to model state errors ?? my post action method will have the following :- `public async Task Create(IEnumerable Question) { if (ModelState.IsValid) {}return View(Question);}` – John John Jun 09 '17 at 13:10
  • so i am not sur if i can post back the answers info insdie the partial view,, when the view is rendered after a model state error.. – John John Jun 09 '17 at 13:54
  • 1
    Yes of course you can. I assume you mean that the `QuestionDesc` and `AnwerDesc` values are not displayed when you return the view which would be because you did not include hidden inputs for them in the view so they are not sent to the server. Either include the inputs or get that data again from the database. –  Jun 09 '17 at 17:37
  • but one last question i can not understand how the code you provided worked internally ??.. as inside the main view i will be passing `IEnumerable` while in the partial view it will be accepting single `Question` object. so when i define `@Html.EditorFor(m => m)` i though this will raise an exception since the partial view is defined to accept a single Question object,, while i will be passing `IEnumerable` .. but i did not get any exception... – John John Jun 12 '17 at 12:46
  • 1
    Because the `EditorFor()` method has an overload that accepts `IEnumerable`. If you pass `IEnumerable` then the method will internally loop through the collection and use the `EditorTemplate` to generate the correct html for each item –  Jun 12 '17 at 21:21