1

I have used scaffolding templates to create the necessary parts in the Controller and the accompanying Views for my Model class Question pictured here:

public class Question
    {
      [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
      public int QuestionId { get; set; }

      [StringLength(250, ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "MaxCharsQuestionAchieved")]
      public string GeneralQuestion { get; set; }

      [StringLength(1000, ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "MaxCharsExplanationAchieved")]
      public string Explanation { get; set; }

      public bool IsTemplate { get; set; }

      public QuestionState QuestionState { get; set; }
      public DateTime DateSubmitted { get; set; }
      public DateTime? JudgementDate { get; set; }

      public virtual Regular Author { get; set; }

      public virtual List<Politician> AddressedPoliticians { get; set; }
      public virtual List<Topic> Topics { get; set; }

      public virtual Moderator LastEditor { get; set; }

      public virtual List<Attachment> Attachments { get; set; }
      public virtual List<Answer> Answers { get; set; }

      public virtual List<QuestionSubscription> QuestionSubscriptions { get; set; }


      public int FbShares { get; set; }
      public int FbLikes { get; set; }
      public int TwitterShares { get; set; }
      public int SiteVotes { get; set; }
}

I'd like to change the template for the Create View. As you can see Question has a list of AddressedPoliticians. I'd like to present the users with a dropdownlist of all the Politicians in my Database. The value has to be the id of the Politician, the display member should be their FirstName. The View has a model of type Question, of course. How can I construct the dropdownlist and give the selected value to my Create(Question question) ActionResult method, so I can get the Politician out of the database to add it to AddressedPOliticians in Question?

I tried fiddling with ViewBag, but can't seem to get it to work. Hope someone can give me some tips/ suggestions.

EDIT:

I should probably show what I already tried :)

ActionResult methods:

public ActionResult Create()
    {
      ViewBag.PolIds = new SelectList(context.Politicians.ToList(), "UserId", "FirstName");
      return View();
    }

    //
    // POST: /Question/Create

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Question question)
    {
      if (ModelState.IsValid)
      {
        var polId = ((SelectList)ViewBag.PolIds).SelectedValue;
        Politician pol = context.Politicians.Single(p => p.UserId == (int)polId);
        question.AddressedPoliticians.Add(pol);
        question.DateSubmitted = DateTime.Now;
        manager.CreateQuestion(question);
        return RedirectToAction("Index");
      }

      return View(question);
    }

Create.cshtml:

@model PoliticiOnline.DTO.Question

@{
    ViewBag.Title = "Stel een vraag!";
}

<h2>Stel een vraag!</h2>

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

    <fieldset>
        <legend>Vraag</legend>

        <div class="general-question">
            <div class="editor-label">
                @Html.LabelFor(model => model.GeneralQuestion, "Algemene Vraag")
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.GeneralQuestion)
                @Html.ValidationMessageFor(model => model.GeneralQuestion)
            </div>
        </div>

        <div class="geadresseerde-politici">
            @Html.Label("Politicus")
            @Html.DropDownList("PolIds", "Kies een politicus...")
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Explanation, "Extra Uitleg")
        </div>
        <div class="editor-field">
            @Html.TextAreaFor(model => model.Explanation)
            @Html.ValidationMessageFor(model => model.Explanation)
        </div>

        <p>
            <input type="submit" value="Indienen!" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}
E. V. d. B.
  • 815
  • 2
  • 13
  • 30

2 Answers2

0

For a Dropdown: Create the values to select from as a List and a property to store the selected value in (probably an int). Then use:

@Html.DropDownListFor(m => m.SelectedValue, Model.SelectListItems)

For a list of checkboxes, you should add a List or similar, containing the selected Politicians ID's. Then add a list of checkboxes with name='name of List', value='id of politictian' and of course the name as the text of the associated label.

An example from one of my own views:

<ul class="fields">
@foreach (var gender in Model.FilterData.Genders)
{
  <li class="field">
    <input id="gender@(gender.Id)" type="checkbox" name="Filters.Genders" value="@gender.Id" @(Model.Filters.Genders.Contains(gender.Id) ? "checked" : "") />
    <label for="gender@(gender.Id)">@gender.Name</label>
  </li>
}
</ul>

Now, I have a list of genders to select from in my Model.FilterData object, having an Id and a Name each. I also have an object "Filters" in my Model, with a List Genders. So as you can see each checkbox has the name "Filters.Genders", i.e. pointing to this list.

If you want to be able to select only one, just create a single int property in your model and bind a range of radiobuttons to the same int property. Again an example:

<ul class="fields">
  @foreach (var function in Model.FilterData.Functions)
  {
    <li class="field">
      @Html.RadioButtonFor(m => m.Filters.FunctionId, function.Id)
      @Html.LabelFor(m => m.Filters.FunctionId, function.Name)
    </li>
  }
</ul>

This is easier as you can use the Helper functions. As you can see, each radiobutton points to the same model property (Filters.FunctionId) - so the rendered inputs all have this as their name.

If used in a GET method, you'll see that it repeats the same property multiple times (i.e. Filters.Genders=2&Filters.Genders=4&Filters.Genders=5) which will be parsed into the List in your action.

mjepson
  • 871
  • 1
  • 9
  • 21
  • And I should really learn to read first ... for a Dropdown: Create the values to select from as a `List` and a property to store the selected value in (probably an int). Then use: `@Html.DropDownListFor(m => m.SelectedValue, Model.SelectListItems)` – mjepson Apr 01 '14 at 09:59
  • I kind of see what you mean, but I don't really see where to fit it into my code :/ I also would like a dropdownlist instead of radiobuttons because will grow in size over time ... Any idea what I should do? – E. V. d. B. Apr 01 '14 at 10:00
  • Ah I see, where does the m refer to? If it's the model than it's not possible because list of all Politicians is not part of the model in the view. – E. V. d. B. Apr 01 '14 at 10:02
  • the m in the lambda does refer to the model, but the selected value should be in your model (otherwise, you have a rather weird design). The list of all politicians is the second parameter, "Model.SelectListItems", which is easily exchangable for "ViewBag.AllPoliticians" or something similar. – mjepson Apr 01 '14 at 10:06
  • So you mean the Politician Id should be in my Question class? – E. V. d. B. Apr 01 '14 at 10:08
  • Since that's the Model you pass to your view, yes. – mjepson Apr 01 '14 at 10:09
  • As long as you're also using the same Model in the Action that processes the form submit. If not, you can use `@Html.DropDownList('field name in action', ViewBag.AllPoliticians)` or something like that. The field name can be either the name of a parameter in the action that processes the submit, or a property of the model that is used in that action. – mjepson Apr 01 '14 at 10:12
0

Add a field in your Question model:

[NotMapped]
public decimal PoliticianId { get; set; }

In your view :

<div class="geadresseerde-politici">
            @Html.Label("Politicus")
@Html.DropDownListFor(model => model.PoliticianId, (SelectList)ViewBag.PolIds)
        </div>

And in your action:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Question question)
    {
      if (ModelState.IsValid)
      {
         var selectedPolitician = question.PoliticianId; // The selected politician id
      }
    }

EDIT:

Or like mjepson mentioned in his comment, you can do it without adding a field to your Question model like :

In your view :

<div class="geadresseerde-politici">
            @Html.Label("Politicus")
@Html.DropDownList("PoliticianId", (SelectList)ViewBag.PolIds)
        </div>

And in your action:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Question question, int PoliticianId) // PoliticianId will now have the selected value of the dropdown
    {
      if (ModelState.IsValid)
      {
         // do your stuff
      }
    }
kelsier
  • 4,050
  • 5
  • 34
  • 49
  • I think adding that field will probably interfere with my Database structure, correct me if I'm wrong! – E. V. d. B. Apr 01 '14 at 10:07
  • you can use `[NotMapped]` attribute, check here http://stackoverflow.com/questions/10385248/ignoring-a-class-property-in-entity-framework-4-1-code-first – kelsier Apr 01 '14 at 10:10
  • @E.V.d.B. You are welcome. Edited my answer to give you another method as mjepson mentioned in his comment. – kelsier Apr 01 '14 at 10:42
  • I tried it out but the politicianId is always 0, any idea waht could be the problem? (I calle selectedPolitician politicianId) – E. V. d. B. Apr 01 '14 at 10:47
  • The view seems alright. I hope `ViewBag.PolIds = new SelectList(context.Politicians.ToList(), "UserId", "FirstName");` doesn't have 0's for UserId? Also check the rendered ` – kelsier Apr 01 '14 at 11:07
  • I get `` which seems kinda weird... – E. V. d. B. Apr 01 '14 at 11:10
  • No, it should be right, the ID's check out, I just checked! So waht could possibly be wrong? – E. V. d. B. Apr 01 '14 at 11:11
  • In that pastebin you have `@Html.DropDownListFor(m => m.PoliticianId, (SelectList)ViewBag.PolIds)`, it should be `@Html.DropDownListFor(model => model.PoliticianId, (SelectList)ViewBag.PolIds)`. Maybe that's the problem? – kelsier Apr 01 '14 at 11:13
  • Just paste all the code in pastebin and post the link here? – kelsier Apr 01 '14 at 11:22