Search code examples
asp.net-mvc-5mvc-editor-templateseditortemplates

EditorTemplates Where or Groupby on Questionnaire


At the moment, I have a working prototype for a questionnaire with multiple questions and each question having multiple choices for an answer. Everything displays and saves great. However, I now would like to group the question/answers into 'sections' on my Edit view. I have tried a couple different methods but nothing seems to work correctly. The working code without sections are as follows:

Edit View Progress Report:

<div class="form-group">
    @Html.LabelFor(model => model.ReportAnswers, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.ReportAnswers)
    </div>
</div>

ReportAnswers.cshtml (editor template)

<h3>
    Question
</h3>

<p>
    @Html.DisplayFor(x => x.Question.QuestionText)
</p>
@Html.HiddenFor(model => model.QuestionID)
@Html.HiddenFor(model => model.ReportID)

@foreach (var answer in Model.Question.PossibleAnswers)
{
    var id = string.Format("answer-{0}", answer.AnswerID);
    <p>
        @Html.HiddenFor(model => model.ReportAnswerID)

        @Html.RadioButtonFor(m => m.AnswerID, answer.AnswerID, new { id = id })
        <label for="@id">@answer.AnswerText</label>
    </p>
}

EditController:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(ProgressReport progressReport)
    {
        if (ModelState.IsValid)
        {
            db.Entry(progressReport).State = EntityState.Modified;
            db.SaveChanges();

            foreach (ReportAnswer answer in progressReport.ReportAnswers)
            {
                        if (answer.QuestionID != null && answer.AnswerID != null)
                        {
                            db.Entry(answer).State = EntityState.Modified;
                            db.SaveChanges();
                        }                   

            }

            return RedirectToAction("Index");
        }
        ViewBag.ClientID = new SelectList(db.Clients, "ClientID", "ID", progressReport.ClientID);
        return View(progressReport);
    }

Data structure is Sections -> Questions -> Answers I then have a ProgressReport table that has QuestionID and AnswerID

I have attempted to Groupby within the view, but then unsure how to call the Editortemplate correctly. In fact, I was able to use it, but the result was not as expected. that code is:

@foreach (var group in Model.ReportAnswers.GroupBy(s => s.Question.SectionID))

Thanks!

Data Structure Snippet: enter image description here


Solution

  • I was able to develop a solution...proper or not..Don't know...but it does work. Feel free to critique. I welcome it. :)

    ProgressReportViewModel:

    public class ProgressReportViewModel
    {
        public int ReportID { get; set; }
        public DateTime ReportDateSubmitted {get; set;}
        public List<ReportAnswer>[] ReportAnswerSection { get; set; }
        public string[] SectionHeadings { get; set; }
        public string[] SectionDescriptions { get; set; }
    }
    

    EditController:

    public ActionResult Edit(int? id)
        {
            var viewModel = new ProgressReportViewModel();
    
           //  Get the section in order of defined display order
            var questionsection = (from s in db.QuestionSections
                                    orderby s.SectionDisplayOrder
                                    select new{
                                        s.SectionName,
                                        s.SectionDesc
                                    });
    
            viewModel.SectionHeadings = new string[11];
            viewModel.SectionDescriptions = new string[11];
            viewModel.ReportAnswerSection = new List<ReportAnswer>[11];
    
            int i = 0;
            foreach(var section in questionsection)
            {
                //  Loop through sections and get the name, desc and the questions/answers
                viewModel.SectionHeadings[i] = section.SectionName.ToString();
                viewModel.SectionDescriptions[i] =   section.SectionDesc;
                viewModel.ReportAnswerSection[i] = db.ReportAnswers.Where(q => q.Question.SectionID == i+1 && q.ReportID == id).Include(s => s.Question.QuestionSection).OrderBy(q => q.Question.DisplayOrder).ToList();
                i=i+1;
            }
    
            var report = (from r in db.ProgressReports
                          where r.ReportID == id
                          select new
                          {
                              r.ReportID,
                              r.ReportDateSubmitted,
                              r.ClientID
                          }).SingleOrDefault();
            viewModel.ReportID = report.ReportID;
            viewModel.ReportDateSubmitted = report.ReportDateSubmitted ?? DateTime.MinValue;
    
    
            return View(viewModel);
        }
    
    
    
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(ProgressReportViewModel progressReport)
        {
            if (ModelState.IsValid)
            {
                ProgressReport PR = db.ProgressReports.Where(x => x.ReportID == progressReport.ReportID).SingleOrDefault();
    
    
                //db.ProgressReports.Attach(progressReport);
    
                db.Entry(PR).State = EntityState.Modified;
                db.SaveChanges();
    
                for (var i = 0; i <= 10; i++ )
                {
                    foreach (ReportAnswer answer in progressReport.ReportAnswerSection[i]) //.ReportAnswers)
                    {
                        SaveAnswers(answer);
                    }
                }
    
                return RedirectToAction("Index", "Home");
            }
            return View(progressReport);
        }
    

    ReportAnswers Editor Template

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

    Edit View:

    @for(var i = 0; i<=10; i++)
        {
            <h4>@Html.DisplayFor(model => model.SectionHeadings[i]) </h4>
            <p>@Html.DisplayFor(model => model.SectionDescriptions[i]) </p>
            @Html.EditorFor(model => model.ReportAnswerSection[i])
        }
    

    I chose to do these arrays because there is one section at least I need to intercept to do something special with. Otherwise all other sections are typical. This seems to work but as stated, I welcome any criticisms anyone may have.

    Have a great day!