How can I bind a dynamic collection of questions with a dynamic collection of answers to a view model?

PJ Slauta 1 Reputation point
2022-02-25T22:07:41.467+00:00

Hi all,
I have an app that is a multiple choice survey. The questions are loaded from a database and the answer choices are also loaded from a database. I want to bind the response to the model, but I'm not sure how to achieve this. Here is my ViewModel and View:

ViewModels:

public class SurveyViewModel : SurveyViewModelBase
    {
        public IEnumerable<SectionViewModel> Sections { get; set; }
        public DemographicQuestionsModel DemographicQuestions { get; set; }
        public string Title { get; set; }
    }
public class SectionViewModel
    {
       public string SectionTitle { get; set; }
       public IEnumerable<QuestionAnswerViewModel> QAs { get; set; }
    }
public class QuestionAnswerViewModel
    {
        public QuestionViewModel Question { get; set; }
        public AnswerViewModel SelectedAnswer { get; set; }
        public IEnumerable<QuestionAnswerViewModel> ChildQuestions { get; set; }
    }
public class QuestionViewModel
    {
        public Guid Id { get; set; }
        public string Text { get; set; }
        public IEnumerable<AnswerViewModel> PossibleAnswers { get; set; }
        public int QuestionNumber { get; set; }
    }
 public class AnswerViewModel
    {
        public Guid Id { get; set; }
        public string AnswerText { get; set; }
    }

View:

@using VSC.ViewModels
@model VSC.ViewModels.SurveyViewModel
@{
    SectionViewModel section = Model.Sections.FirstOrDefault();
}
<div class="row">
    <div class="sectionTitle">@(section.SectionTitle)</div>
</div>
<form action="/VSC/Survey">
    @foreach (var qa in section.QAs)
    {
        if (qa.Question.QuestionNumber == 0)
        {
            <div class="row question">
                @qa.Question.Text
            </div>
        }
        else
        {
            if (qa.ChildQuestions != null)
            {
                <div class="row question child-question @(qa.Question.QuestionNumber==null?"parent-question":"")">
                </div>
            }
            else
            {
                <div class="row question @(qa.Question.QuestionNumber==null?"parent-question":"")">
                    @qa.Question.QuestionNumber  @qa.Question.Text
                </div>
            }
            <div class="row answers">
                @foreach (var answer in qa.Question.PossibleAnswers)
                {
                    <div class="answer">
                        @{

                            <div class="answer">
                                <label>
                                    @answer.AnswerText
                                    @Html.RadioButtonFor(m=>qa.SelectedAnswer, answer.Id)
                                </label>
                            </div>
                            <div class="answer">
                                <label>

                                </label>
                            </div>
                        }
                    </div>
                }
            </div>
        }

    }
    <input type="submit" value"Submit" />
</form>

Naturally, this produces radio buttons with all the same names, so when I click on one for a given question, the previous questions radio button unchecks and the new question is now the only one with a selection.

Any help is appreciated.

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,674 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Zhi Lv - MSFT 32,646 Reputation points Microsoft Vendor
    2022-02-28T05:51:47.46+00:00

    Hi @PJ Slauta ,

    You could refer the following steps to modify your code:

    1. Change the IEnumerable to List in the model.
    2. Use View Model ( @Model )and for statement to bind the properties.
    3. Since you might want to submit the form, it is better to use hidden field to store the other properties.

    After modified, the Model like this: In the QuestionViewModel model, add a SelctedAnswer property to store the selected answer for each question.

    public class SurveyViewModel  
    {  
        public List<SectionViewModel> Sections { get; set; }   
        public string Title { get; set; }  
    }  
    public class SectionViewModel  
    {  
        public string SectionTitle { get; set; }  
        public List<QuestionAnswerViewModel> QAs { get; set; }  
    }  
    public class QuestionAnswerViewModel  
    {  
        public QuestionViewModel Question { get; set; }  
        public AnswerViewModel SelectedAnswer { get; set; }  
        public List<QuestionAnswerViewModel> ChildQuestions { get; set; }  
    }  
    public class QuestionViewModel  
    {  
        public Guid Id { get; set; }  
        public string Text { get; set; }  
        public List<AnswerViewModel> PossibleAnswers { get; set; }  
        public string SelctedAnswer { get; set; }  
        public int QuestionNumber { get; set; }  
    }  
    public class AnswerViewModel  
    {  
        public Guid Id { get; set; }  
        public string AnswerText { get; set; }  
    }  
    

    The view page:

    @model WebApplication1.Models.SurveyViewModel  
       
     <div class="row">  
         <div class="sectionTitle">@(Model.Sections.FirstOrDefault().SectionTitle)</div>  
     </div>  
        
      
     <form action="/Home/Survey" method="post">   
         <input type="hidden" asp-for="@Model.Title"  />  
         @for (var i = 0; i<  Model.Sections.FirstOrDefault().QAs.Count(); i++)  
         {   
             var qa = Model.Sections.FirstOrDefault().QAs;  
               
             <input type="hidden" asp-for="@Model.Sections[0].SectionTitle"  />  
             @if (qa[i].Question.QuestionNumber == 0)  
             {  
                 <div class="row question">  
                     @qa[i].Question.Text  
                 </div>  
             }  
             else  
             {  
                 if (qa[i].ChildQuestions != null)  
                 {  
                     <div class="row question child-question @(qa[i].Question.QuestionNumber==null?"parent-question":"")">  
                     </div>  
                 }  
                 else  
                 {  
                     <div class="row question @(qa[i].Question.QuestionNumber==null?"parent-question":"")">  
                         @qa[i].Question.QuestionNumber  @qa[i].Question.Text  
                     </div>  
                 }  
                   
                 <input type="hidden" asp-for="@Model.Sections[0].QAs[i].Question.Id"  />  
                 <input type="hidden" asp-for="@Model.Sections[0].QAs[i].Question.QuestionNumber"  />  
                 <input type="hidden" asp-for="@Model.Sections[0].QAs[i].Question.Text"  />  
                 <div class="row answers">  
                     @for (var j = 0; j<  qa[i].Question.PossibleAnswers.Count(); j++)  
                     {  
      
                        <input type="hidden" asp-for="@Model.Sections[0].QAs[i].Question.PossibleAnswers[j].Id"  />  
                        <input type="hidden" asp-for="@Model.Sections[0].QAs[i].Question.PossibleAnswers[j].AnswerText"  />  
      
                         <div class="answer">  
                             @{  
                                   var answer = qa[i].Question.PossibleAnswers[j];  
      
                                 <div class="answer">  
                                     <label>  
                                         @qa[i].Question.PossibleAnswers[j].AnswerText  
                                         <input type="radio" asp-for='@Model.Sections[0].QAs[i].Question.SelctedAnswer' value="@answer.Id" />   
                                     </label>  
                                 </div>  
                                 <div class="answer">  
                                     <label>  
          
                                     </label>  
                                 </div>  
                             }  
                         </div>  
                     }  
                 </div>  
             }  
          
         }  
         <input type="submit" value"Submit" />  
     </form>  
    

    The result is like this:

    178229-1.gif


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Dillion

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.