How to set the selected value in EnumDropDownListFor? - asp.net-mvc-5.1

I'm using MVC 5.2.0 and I'm trying to use the new Html.EnumDropDownListFor. This is how I'm setting the values:
//Model
public class MyModel {
public int SelectedEnumId { get; set; }
public TestEnum MyEnum { get; set; }
}
//Enum
public enum TestEnum : int
{
name1 = 1,
name2 = 2
}
//View
#Html.EnumDropDownListFor(model => model.MyEnum,new { #class = "form-control" })
This is working and the values are being displayed. But how do I set the selected value (SelectedEnumId)?
Normally I would use
//Not enum
#Html.DropDownListFor(model => model.SelectedId, new SelectList(Model.myvalues, "Value", "Text"))
Is there a way to do this with the new Helper in MVC 5.1-5.2? Or I have to create a Extension method for this?

As far as I know just make sure the value you want to be selected is set in your Model before you call
//Controller:
...
myModel.TestEnum = TestEnum.name2;
...
//On your view
...
#Html.EnumDropDownListFor(model => model.TestEnum);
...

Could NOT get the option selected in the controller to display on the front end either, so had to resort to setting a temporary hidden input and used jQuery to update on the client side:
<div class="form-group">
#Html.LabelFor(model => model.MyEnum, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EnumDropDownListFor(model => model.MyEnum, "Select name", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.MyEnum, "", new { #class = "text-danger" })
</div>
#Html.Hidden("MyEnumTemp", (int)Model.MyEnum)
<script>
$(function () {
$("#MyEnum").val($("#MyEnumTemp").val());
});
</script>

Just Use This in Your Controller, It works like a charm
MyModel.TestEnum = (TestEnum)SelectedEnumId;
Not This will work fine assuming the case, that SelectedEnumId > 0.
if(SelectedEnumId > 0) {
MyModel.TestEnum = (TestEnum)SelectedEnumId;
}

public class MyModel{
public int SelectedEnumId { get { return Convert.ToInt32(this.MyEnum); } }
public TestEnum MyEnum { get; set; }
}
//add your model and after use DropDownList with EnumHelper, behaves asEnumDropDownListFor
#Html.DropDownListFor(model => model.SelectedEnumId, EnumHelper.GetSelectList(typeof(TestEnum)),new { #class="form-control" })

I know this thread is old, but I have same issue today and got it fixed; so just wanna share my codes.
you are so closed actually, all you need is to add EnumHelper.GetSelectList inside new SelectList.
//Model
public class MyModel {
public int SelectedEnumId { get; set; }
}
//Enum
public enum TestEnum
{
name1 = 1,
name2 = 2
}
//View
// get default value
var selectedID = Model.MyModel.SelectedEnumId.ToString();
// dropdown list
#Html.DropDownListFor(model => model.MyModel.SelectedEnumId, new SelectList(EnumHelper.GetSelectList(typeof(TestEnum)), "Value", "Text", selectedID), new { #class = "form-control" })
EnumHelper.GetSelectList will assign Text and Value attributes to Enum class, and use SelectedValue property of SelectList for default selected option.
Hope this will help someone. Thanks

Related

Set The selected Value of a Multiselect from Controller to View after submitting an invalid Model

I am using a Multiselect DropDownList to generate a multiple <select>
I was able to generate it and was working fine.
But If I try to submit it using the parameters:
Name = null
ObjAOption = [1,2] // assume I selected 2 options in my multiselect
ObjAOption will just select option value='1' instead of select options 1, and 2.
Is there any way I can get back the selected options and pass it back to my view by setting it in my controller? I would love to use HTML helper and not to use jQuery or javascript on this part.
Controller:
public ActionResult AddObjectA(AddModel am){
if(ModelState.IsValid){
//Save
}
else {
am.ObjA = // new List of ObjectA with atleast 4 option
return View("MyView",am);
}
}
View:
#Html.LabelFor(model => model.ObjA, "Object A")
#Html.DropDownList("ObjAOption", new MultiSelectList(Model.ObjA, "Key", "Name"), "-- Select Object A--", new { #class = "custom-select custom-select-sm", multiple="" })
#Html.ValidationMessageFor(m => m.ObjAOption, "", new { #class = "text-danger" })
Model:
public class AddModel {
[Required]
public String Name {get;set;}
public IEnumerable<ObjectA> ObjA{ get; set; }
[Required(ErrorMessage = "Please select at least one option")]
public List<int>ObjAOption{ get; set; }
}
public class ObjectA {
public int Key {get;set;}
public string Name {get;set;}
}
Have you tried to use the helper Hiddenfor ? It generate a field that keep your element value, name and attribute :
View:
#Html.LabelFor(model => model.ObjA, "Object A")
#Html.DropDownList("ObjAOption", new MultiSelectList(Model.ObjA, "Key", "Name"), "-- Select Object A--", new { #class = "custom-select custom-select-sm", multiple="" })
#Html.ValidationMessageFor(m => m.ObjAOption, "", new { #class = "text-danger" })
#Html.HiddenFor(m => m.ObjAOption)
Solution:
I scrapped out my DropDownList and tried using ListBoxFor as discussed here

MVC Dynamic View Binding to Dictionary of Properties for Known and Unknown properties

I have been trying to find a solution to a situation that I'm busy designing, however I have not managed to get to it.
Imagine having the following model
public enum InputType
{
TextInput,
LookupInput
}
public struct AdditionalProperty
{
public string Key {get;set;}
public string Value {get;set;}
public InputType Type {get;set;}
}
public class Person
{
public string FirstName {get;set;}
public List<AdditionalProperty> AdditionalProperties {get;set;}
}
Then, having the following controller
public class HomeController
{
public ActionResult Index()
{
var model = new Person { FirstName = "MyName" };
model.AdditionalProperties = new List<AdditionalProperty>();
var listItem = new AdditionalProperty
{
Key = "Surname",
Value = "MySurname"
};
model.AdditionalProperties.Add(listItem);
return View(model)
}
}
What I'm looking for is the Razor view code on how to "dynamically" create the properties with the correct input type, bound to something in order for me to be able to still use the model when the form gets posted back to the controller for a Save function.
So the property that is known, would be something like this:
<div class="form-group">
<div class="form-row">
<div class="col-md-6">
#Html.LabelFor(model => model.FirstName, new { #class = "control-label" })
<div>
#Html.TextBoxFor(model => model.FirstName, new { #class = "form-control", placeholder = "Enter Group Name", type = "text" })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
</div>
</div>
</div>
The Idea would then be to have the following. Obviously the below isn't sufficient, and this is where I need the help.
I would like to show the additional properties, one below the other, each on a separate line (using bootstrap row) based on the property.InputType
#foreach (var property in Model.Properties)
{
#Html.LabelFor(model => property.Key, new { #class = "control-label" })
<div>
#if (property.InputType == TextInput)
{
#Html.TextBoxFor(model => property.Value, new { #class = "form-control", placeholder = "Enter Group Name", type = "text" })
}
#Html.ValidationMessageFor(model => property.Key, "", new { #class = "text-danger" })
</div>
}
Thus, I would like to see my view as:
| <label> | <input>
Known Property | FirstName | MyFirstName
Unknown Property | Surname | MySurname
In terms of completeness, I am posting the following answer.
I am going to post the Model, View (Index & EditorTemplates) & Controller to show the complete working solution that I used to test the answer that was given to me.
My Model class for this test
Person.cs
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<AdditionalProperty> AdditionalProperties { get; set; }
}
AdditionalProperty.cs
public struct AdditionalProperty
{
public string Key { get; set; }
public object Value { get; set; }
public DateTime? DateValue
{
get
{
DateTime dateValue;
if (DateTime.TryParse(Value?.ToString(), out dateValue))
{
return dateValue;
}
return null;
}
set => Value = value;
}
public InputType InputType { get; set; }
public List<SelectListItem> ValueLookupItems { get; set; }
}
The reason I have a separate DateValue property here is to assist the browser when doing DateTime binding otherwise the DateTimePicker doesn't show.
I used an enum to determine what type of input type this specific property should make use of.
InputType.cs
public enum InputType
{
TextBox,
DropdownBox,
TextArea,
DateSelection,
}
In order to keep the views as simple as possible, Stephen provided me with a sample for the Index View as well as an EditorTemplate for the AdditionalProperty object. The EditorTemplate is used for separation of concerns and to ensure that all the logic behind what input type is being used is in one place.
I have found that the DateTime property doesn't work well, so an additional EditorTemplate was required. I got this from this post.
DateTime.cshtml
Note: Location of template -> /Views/Shared/EditorTemplates
#model DateTime
#{
IDictionary<string, object> htmlAttributes;
object objAttributes;
if (ViewData.TryGetValue("htmlAttributes", out objAttributes))
{
htmlAttributes = objAttributes as IDictionary<string, object> ?? HtmlHelper.AnonymousObjectToHtmlAttributes(objAttributes);
}
else
{
htmlAttributes = new RouteValueDictionary();
}
htmlAttributes.Add("type", "date");
String format = (Request.UserAgent != null && Request.UserAgent.Contains("Chrome")) ? "{0:yyyy-MM-dd}" : "{0:d}";
#Html.TextBox("", Model, format, htmlAttributes)
}
AdditionalProperty.cshtml
Note: Location of template -> /Views/Shared/EditorTemplates
Note: The location of my AdditionalProperty formed part of the DynamicViewExample.Models namespace
#model DynamicViewExample.Models.AdditionalProperty
<div>
#Html.HiddenFor(m => m.Key)
#Html.LabelFor(m => m.Key, Model.Key, new {#class = "control-label"})
#if (Model.InputType == DynamicViewExample.Models.InputType.TextBox)
{
#Html.TextBoxFor(m => m.Value, new {#class = "form-control"})
}
else if (Model.InputType == DynamicViewExample.Models.InputType.TextArea)
{
#Html.TextAreaFor(m => m.Value, new {#class = "form-control"})
}
else if (Model.InputType == DynamicViewExample.Models.InputType.DropdownBox)
{
#Html.DropDownListFor(m => m.Value, Model.ValueLookupItems, new {#class = "form-control"})
}
else if (Model.InputType == DynamicViewExample.Models.InputType.DateSelection)
{
#Html.EditorFor(m => m.DateValue, new {#class = "form-control"})
}
else
{
#Html.HiddenFor(m => m.Value) // we need this just in case
}
</div
This would be how the Index.cshtml file would look
#model DynamicViewExample.Models.Person
#{
ViewBag.Title = "Home Page";
}
#using (Html.BeginForm())
{
<div class="row">
#Html.LabelFor(model => model.FirstName, new { #class = "control-label" })
#Html.TextBoxFor(model => model.FirstName, new { #class = "form-control", placeholder = "Enter Group Name", type = "text" })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
<div class="row">
#Html.LabelFor(model => model.LastName, new { #class = "control-label" })
#Html.TextBoxFor(model => model.LastName, new { #class = "form-control", placeholder = "Enter Group Name", type = "text" })
#Html.ValidationMessageFor(model => model.LastName, "", new { #class = "text-danger" })
</div>
<div class="row">
#Html.EditorFor(m => m.AdditionalProperties, new { htmlAttributes = new { #class = "form-control"}})
</div>
<input type="submit" class="btn btn-primary" />
}
And then finally, the HomeController.cs file contains a Get and Post that allows the ability to manipulate the data as you please. What is missing here is the "dynamic" way of populating the model, but that will naturally happen once a DB has been introduced into the mix.
[HttpGet]
public ActionResult Index()
{
var model = new Person
{
FirstName = "Gawie",
LastName = "Schneider",
AdditionalProperties = new List<AdditionalProperty>
{
new AdditionalProperty {Key = "Identification Number", Value = "1234567890123456", InputType = InputType.TextBox},
new AdditionalProperty {Key = "Date Of Birth", Value = DateTime.Today, InputType = InputType.DateSelection},
new AdditionalProperty {Key = "Age", Value = "31", InputType = InputType.TextBox},
new AdditionalProperty {Key = "Gender", Value = "Male", InputType = InputType.DropdownBox,
ValueLookupItems = new List<SelectListItem>
{
new SelectListItem{Text = "Male", Value = "Male"},
new SelectListItem{Text = "Female", Value = "Female"}
}},
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(Person model)
{
//Do some stuff here with the model like writing it to a DB perhaps
return RedirectToAction("Index");
}
So if I would have to sum up what I was trying to do here.
The goal I wanted to achieve was to be able to make use of Strongly Typed / Known Properties in conjunction with Dynamic / Unknown Properties to create a system that would allow the user to create new inputs on the fly without the need for a developer to be involved.
I honestly hope that this might help someone else as well some day.
Enjoy the coding experience
Gawie

How to save dropdownlist selected value to the database int asp.net MVC 5

I am currently new to Asp.net MVC .In one of the view I add a dropdownlist and I bind this dropdownlist with my database like this
Controller CollegeController
[HttpGet]
public ActionResult Create()
{
IEnumerable<SelectListItem> items = db.College_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Name });
IEnumerable<SelectListItem> item = db.Stream_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Stream });
ViewBag.CollName=items;
ViewBag.StreamName = item;
return View();
}
[HttpPost]
public ActionResult Create(College college)
{
try
{
if(ModelState.IsValid)
{
db.Colleges.Add(college);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CollName = db.Colleges;
return View(college);
}
catch
{
return View();
}
}
This is my model
public class College
{
[Required]
public int Id { get; set; }
[Required]
[Display(Name="College Name")]
public int CollegeName { get; set; }
[Required]
public int Stream { get; set; }
[Required]
[Column(TypeName="varchar")]
public string Name { get; set; }
....
public virtual College_Name College_Name { get; set; }
public virtual Stream_Name Stream_Name { get; set; }
}
This is My View
<div class="form-group">
#Html.LabelFor(model => model.CollegeName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CollName", (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CollegeName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Stream, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("StreamName", (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Stream, "", new { #class = "text-danger" })
</div>
</div>
Now when I check my database after I save the CollegeName and Stream in the database is zero from the dropdownlist.
You have multiple problems with your code. Firstly you dropdownlists are binding to a properties named CollName and StreamName which do not even exist in your model.
Next you cannot name the property your binding to the same as the ViewBag property.
Your view code would need to be (and always use the strongly typed xxxFor() HtmHelper methods
#Html.DropDownListFor(m => m.CollegeName, (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
....
#Html.DropDownListFor(m => m.Stream, (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" }
and in your POST method, the values of college.CollegeName and college.Stream will contain the ID's of the selected options.
You also need to repopulate the ViewBag properties when you return the view in the POST method (as you did in the GET method) or an exception will be thrown (and note that your current use of ViewBag.CollName = db.Colleges; will also throw an exception)
I also strongly suggest you start learning to use view models (views for editing should not use data models - refer What is ViewModel in MVC?) - and use naming conventions that reflect what your properties are, for example CollegeNameList, or CollegeNames, not CollName

MVC5 problems with DropDownList and view model

So I have a simple database table in the form of ID, EmployeeID, date etc. Which creates a normal model:
public partial class WorkItem
{
public int ID { get; set; }
public int EmployeeID { get; set; }
public int LocationID { get; set; }
[DataType( DataType.Date )]
[Display( Name = "Start date" )]
public System.DateTime StartDate { get; set; }
My problem occurs when I need to augment the functionality of this model and so I create a view model to group work items on a weekly basis.
public class WeeklyWorkItemsViewModel
{
public WorkItem WorkItemMonday { get; set; }
public WorkItem WorkItemTuesday { get; set; }
All works perfectly well for the DateTime field in my view (which is bound to the view model):
<div class="form-group">
#Html.LabelFor( model => model.WorkItemMonday.StartDate, "Week start date", htmlAttributes: new { #class = "control-label col-md-2" } )
<div class="col-md-10">
#Html.EditorFor( model => model.WorkItemMonday.StartDate, new { htmlAttributes = new { #class = "form-control" } } )
#Html.ValidationMessageFor( model => model.WorkItemMonday.StartDate, "", new { #class = "text-danger" } )
</div>
</div>
The problem occurs trying to bind the dropdownlilst, it gets populated correctly but the changes are not seen in the controller.
<div class="form-group">
#Html.LabelFor( model => model.WorkItemMonday.EmployeeID, "EmployeeID", htmlAttributes: new { #class = "control-label col-md-2" } )
<div class="col-md-10">
#Html.Hidden( "selectedEmployee" )
#Html.DropDownList( "EmployeeID", null, htmlAttributes: new { #class = "form-control" } )
#Html.ValidationMessageFor( model => model.WorkItemMonday.EmployeeID, "", new { #class = "text-danger" } )
</div>
</div>
The StartDate is updated in the controller.
After mucho head scratching, I finally had to get around this using:
#Html.Hidden( "selectedEmployee" )
And updating this in JQuery. I did try using #html.DropDownListFor but no joy so far.
Can anyone see what's wrong before I pull ALL my hair out.
You model does not contain a property named EmployeeID. But it does have ones named WorkItemMonday.EmployeeID and WorkItemTuesday.EmployeeID.
Stop using DropDownList() and use the strongly typed DropDownListFor() method so that you correctly bind to your model properties.
Modify you view model to include a property for the SelectList
public IEnumerable<SelectListItem> EmployeeList { get; set; }
and populate it in the GET method before you pass the model to the view. Then in the view use
#Html.DropDownListFor(m => m.WorkItemMonday.EmployeeID, Model.EmployeeList, new { #class = "form-control" })
....
#Html.DropDownListFor(m => m.WorkItemTuesday.EmployeeID, Model.EmployeeList, new { #class = "form-control" })
which will correct generate the name="WorkItemMonday.EmployeeID" and name="WorkItemTuesday.EmployeeID" attributes so that they will bind to your model when you post.

Pass Select into Controller via Response

Hy,
I'm new to ASP.NET MVC 5. I'm trying to get the value of an HTML select with no success.
My View (essential part):
<div class="form-group">
#Html.Label("Country", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownList("Countries", (IEnumerable<SelectListItem>)ViewBag.Countries, new { #class = "form-control", id = "Country", name = "Country" })
</div>
</div>
My Controller (essential part):
public ActionResult Index()
{
string country = Request["Country"]; // here I always get null
}
I need a newbie like explanation why this is not working and how I get it to work, please :)
First, I agree with #Maess. Don't use ViewBag. It's horrible and someone at Microsoft should be slapped for ever adding it as an option in the first place.
That said, your error is pretty obvious here. You named your select "Countries" and you're trying to pull "Country" out of the request.
Since you're new, I'll be nice and lay out how to use a view model for this. First, create a model:
public class IndexViewModel
{
public int SelectedCountry { get; set; }
public IEnumerable<SelectListItem> CountryChoices { get; set; }
}
Then in your action:
// GET
public ActionResult Index()
{
var model = new IndexViewModel();
// get your country list somehow
// where `Id` and `Name` are properties on your country instance.
model.CountryChoices = countries.Select(m => new SelectListItem { Value = m.Id, Text = m.Name });
return View(model);
}
And in your view:
#model Namespace.IndexViewModel
...
#Html.DropDownListFor(m => m.SelectedCountry, Model.CountryChoices, new { #class = "form-control" })
And finally, in your POST action:
[HttpPost]
public ActionResult Index(IndexViewModel model)
{
// use model.SelectedCountry
}

Resources