2

I'm making a survey application. Survey has Questions and Questions have QuestionOption. haveThere is a example here. I am trying to use this technique in a large form with a list(List) but when I post back, the Viewmodel.Order that should’ve contained list of items and activities return with the lists empty.

My QuestionModel.cs like this.

 public int Id { get; set; }       
 public string QuestionText { get; set; }     
 public System.Nullable<bool> OptionType1 { get; set; }
 public System.Nullable<bool> OptionType2 { get; set; }
 public List<QuestionOptionModel> OptionList = new List<QuestionOptionModel>();

When I post back "IEnumerable questions" List OptionList comes null. How can I do this?

 public ActionResult CallSurvey()
    {
        IEnumerable<QuestionModel> questionModelList = (IEnumerable<QuestionModel>)SessionHelper.GetSessionObject(SessionKeys.SurveyKey);
       questionModelList = questionSrv.GetQuestionModel();
        return View(questionModelList);

    }

questionModelList include all my survey question and question options. When I post it, post back is coming with only null optionList.

 [HttpPost]
    public ActionResult CallSurvey(IEnumerable<QuestionModel> questions)
    { ..... }

CallSurvey.cshtml

   <body>
    @using ((Html.BeginForm()))
    {
        @ViewBag.Test
        <section class="slides layout-regular template-kendo">
        @foreach (var item in Model)
        {<article>

                @Html.Partial("QuestionEditor", item)
               </article>
        }
   <div class="slide-area" id="prev-slide-area"></div>
        <div class="slide-area" id="next-slide-area"></div>
      </section> 
    }
</body>

QuestionEditor.cshtml

    @model LSMM.Business.Model.Survey.QuestionModel
@using LSMM.Web.Helpers
<div>
    @using (Html.BeginCollectionItem("Questions"))
    {

        <table id="table1">
            <tr>
                <td>
                    <div id="@Model.Id" class="hint">
                        @Html.HiddenFor(m => m.Id)
                        @Html.HiddenFor(m => m.QuestionText)
                        @Html.HiddenFor(m => m.OptionType1)
                        @Html.HiddenFor(m => m.OptionType2)



                        @for (int i = 0; i < Model.OptionList.Count; ++i)
                        {
                        @Html.LabelFor(m => m.OptionList[i].Id)
                        @Html.LabelFor(m => m.OptionList[i].QuestionId)
                        @Html.LabelFor(m => m.OptionList[i].Checked)
                        @Html.LabelFor(m => m.OptionList[i].Description)
                        @Html.LabelFor(m => m.OptionList[i])
                   }
                        <span id="sorular">@Model.Id. @Model.QuestionText</span>
                        <br />
                        <br />
                    </div>
                </td>
            </tr>
            <tr>
                <td>
                    <div class="hint2">
                        @Html.Partial("QuestionOptionEditor", Model)
                    </div>
                </td>
                <td>
                    <div id="@Model.Id-Img">
                        <h2 style="top: 200px; right: 0;">
                            <img src="../../Content/css/img/@Model.Id-Img.png"></h2>
                    </div>
                </td>
            </tr>
        </table>  

and QuestionOptionEditor.cshtml

   @model LSMM.Business.Model.Survey.QuestionModel

 @using LSMM.Web.Helpers               



@foreach (var option in @Model.OptionList)
{


    <p>
        @if (@Model.OptionType1 == false)
        { 
            @Html.Partial("QuestionOptionModel", option)

        }
        else
        { 
            @Html.Partial("../Shared/DisplayTemplates/QuestionOptionModel", option)

        }
    </p>

}

Here QuestionOptionModel views like this;

@model LSMM.Business.Model.Survey.QuestionOptionModel

      @(Html.RadioButtonFor(m => m.Id, true, new { Id = @Model.Id, Name = @Model.QuestionId })) @Html.Label("Evet")  
      <br /> 
      <br />
      @(Html.RadioButtonFor(m => m.Id, false ,new { Id=@Model.Id, Name = @Model.QuestionId})) @Html.Label("Hayır")
sbb
  • 529
  • 3
  • 25

2 Answers2

2

The name attribute on your radio buttons is not "correct" according to the naming rules used by the default ModelBinder. That's why you aren't seeing the values you expect, the ModelBinder couldn't find what it was looking for.

This is easy to fix and you should end up with less code. Take advantage of the framework and let it do work for you:

  1. MVC can loop IEnumerables for you. Let it. There's little reason to write foreach loops in views these days.
  2. Get rid of those partials. Use MVC's Templates feature instead.

Then your view can be as simple as:

 <body>
        @using ((Html.BeginForm()))
        {
            @ViewBag.Test
            <section class="slides layout-regular template-kendo">
        <table id="table1">
            @* Table header goes here *@
            @Html.EditorFor(model => model.OptionList)
        </table>
       <div class="slide-area" id="prev-slide-area"></div>
            <div class="slide-area" id="next-slide-area"></div>
          </section> 
        }
</body>

When you use an EditorTemplate or a DisplayTemplate, MVC will automatically fix the name attribute on your form fields. It won't do that with a partial.

Another suggestion, also if you don't mind. Get rid of those nulla-bools on your model and write different QuestionOptionModel types. DisplayTemplate/EditorTemplates are wise to the type system and MVC will pick the template that matches the type it is presented.

So you could have another class that derives from QuestionOptionModel:

public class ExtendedQuestionOptionModel : QuestionOptionModel
{
    //Stuff goes here.
}

and you could have a List<QuestionOptionModel> hanging off your model that contains:

  • QuestionOptionModel
  • ExtendedQuestionOptionModel
  • QuestionOptionModel

and when you do this:

@Html.EditorFor(model => model.QuestionOptions)

MVC will go through the option list and render the Editor Template for QuestionOptionModel, then the Editor Template for ExtendedQuestionOptionModel, then the Editor Template for QuestionOptionModel again.

The game you want to play is to try to minimize the C# code in the views, because the views cannot be unit tested. Code that isn't unit tested will eventually come back and get you.

ntcolonel
  • 900
  • 7
  • 10
0

Your question is abit ambiguous. Frankly i hope this is what you are loooking for :
IEnumerable can be transformed to list using

 List<foo>listFoo =iEnumerableEntityFoo.toList() 
Mihai Labo
  • 1,082
  • 2
  • 16
  • 40