Home > Mobile >  How can I bind a dynamic collection of questions with a dynamic collection of answers to a view mode
How can I bind a dynamic collection of questions with a dynamic collection of answers to a view mode

Time:02-27

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 >
     <div >@(section.SectionTitle)</div>
 </div>
 <form action="/VSC/Survey">
     @foreach (var qa in section.QAs)
     {
         if (qa.Question.QuestionNumber == 0)
         {
             <div >
                 @qa.Question.Text
             </div>
         }
         else
         {
             if (qa.ChildQuestions != null)
             {
                 <div parent-question":"")">
                 </div>
             }
             else
             {
                 <div parent-question":"")">
                     @qa.Question.QuestionNumber  @qa.Question.Text
                 </div>
             }
             <div >
                 @foreach (var answer in qa.Question.PossibleAnswers)
                 {
                     <div >
                         @{
    
                             <div >
                                 <label>
                                     @answer.AnswerText
                                     @Html.RadioButtonFor(m=>qa.SelectedAnswer, answer.Id)
                                 </label>
                             </div>
                             <div >
                                 <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.

CodePudding user response:

You will need to specify the index in each ienumerable's input field. It is much better if you use for loop, but with your current code it could be done like this;

See the code below where to create index variables, then manually create a radio button with the indexes.

@foreach (var qa in section.QAs)
{
   // create the QA index
   int indexQA = 0;

   if (qa.Question.QuestionNumber == 0)
   {
      ...
   }
   else
   {
      ...
      <div >
         @foreach (var answer in qa.Question.PossibleAnswers)
         {
            // create possible answers index
            int indexPA = 0;
 
            <div >
            @{
               <div >

                  // create label for, with index
                  <label for="QA[@indexQA]PA[@indexPA]">
                     @answer.AnswerText
                  </label>

                  // create radio button, with index
                  <input type="radio" id="QA[@indexQA]PA[@indexPA]" name="Sections[0].QAs[@indexQA].Question.SelectedAnswer.Id" data-index="QA[@indexQA]"  value="@answer.Id">

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

             // increment possible answers index
             indexPA  ;
          }
       </div>
    }
    
    // increment QA index
    indexQA  ;
}

Since the radio buttons have different name attributes, they will not be grouped with each other, so we need to make a script that unchecks the others.

@section scripts{
   <script>
      $(document).ready(function(){
         $(".possible-answer").change(function(){
            var dataValue1 = $(this).data("index");
            
            // loop through all possible answers and check their data-index
            $(".possible-answer").each(function(){
               var dataValue2 = $(this).data("index");
               
               // if they have the same index, they belong to the same group, uncheck
               if(dataValue1 == dataValue2)
               {
                  $(this).prop("checked", false);
               }
            });
            
            // check the current clicked one
            $(this).prop("checked", true);
         });
      });
   </script>
}
  • Related