Issues in enum values in MVC4 - c#

hi all i am try to make a dropdown list using enum values. I have a select field in to my html page like,
<select name="Mem_BloodGr" >
<option value="A+">A+</option><option value="A-">A-</option>
<option value="B+">B+</option><option value="B-">B-</option>
<option value="O+">O+</option><option value="O-">O-</option>
<option value="AB+">AB+</option><option value="AB-">AB-</option>
</select>
This is repeated in many places in my web page. So i am try to generate dropdown list using enum values
namespace .....Models
{
public class MemberData
{
public int Id { get; set; }
public string Mem_NA { get; set; }
........
public BloodGroup Mem_BloodGr { get; set; }
}
public enum BloodGroup
{
A+, //// **error shows here like, "} expected"**
A-,
B-,
B+
}
}
but i got an error when adding enum values . Can anybody please help me.And is that the right way to creating this type dropdown list or any other easy ways in MVC4???

Here is my approach for dropdown for enums:
Make our own attribute:
public class EnumDescription : Attribute
{
public string Text { get; private set; }
public EnumDescription(string text)
{
this.Text = text;
}
}
Make a helper class:
public static class SelectListExt
{
public static SelectList ToSelectList(Type enumType)
{
return ToSelectList(enumType, String.Empty);
}
public static SelectList ToSelectList(Type enumType, string selectedItem)
{
List<SelectListItem> items = new List<SelectListItem>();
foreach (var item in Enum.GetValues(enumType))
{
FieldInfo fi = enumType.GetField(item.ToString());
var attribute = fi.GetCustomAttributes(typeof(EnumDescription), true).FirstOrDefault();
var title = attribute == null ? item.ToString() : ((EnumDescription)attribute).Text;
// uncomment to skip enums without attributes
//if (attribute == null)
// continue;
var listItem = new SelectListItem
{
Value = ((int)item).ToString(),
Text = title,
Selected = selectedItem == ((int)item).ToString()
};
items.Add(listItem);
}
return new SelectList(items, "Value", "Text", selectedItem);
}
}
Enum itself:
public enum DaylightSavingTime
{
[EnumDescription("Detect automatically")]
Auto = 0,
[EnumDescription("DST always on")]
AlwaysOn = 1,
[EnumDescription("DST always off")]
AlwaysOff = 2
}
You can put everything you want in EnumDescription
Usage:
#Html.DropDownList(
"dst",
SelectListExt.ToSelectList(typeof(DaylightSavingTime)),
new {
id = "dst",
data_bind = "value: Dst"
})
Note: data_bind is transformed to "data-bind". It's useful is you use Knockout.js
You can omit the latest new {} block

You can't have + and - in enum values, just letters and numbers. Use APlus or something instead. You could use enums as a source for a dropdown, but I would recommend a list of object that has a name instead. This way you have more control over what is displayed and you are able to use any character in the names. Use something like this to fill the dropdown with:
public class BloodGroup
{
public string Name {get; set; }
// other properties
}
Then you can create a list of BloodGroup-objects that you can reuse in your views:
var BloodGroupList = new List<BloodGroup> { new BloodGroup { Name = "A+"}, new BloodGroup { Name = "A-"}, ... };
And in your views:
#Html.DropDownList("BloodGroups", BloodGroupList.Select(b => new SelectListItem { Name = b.Name, Value = b.Name }))

Related

How to send an object through #change="" (instead of sending value) when using select element

new to Blazor and I have a simple question
In my Blazor app, I have a simple select element:
<select class="form-select" aria-label="Default select example" #onchange="ItemSelected">
<option selected>Open this select menu</option>
#foreach(var item in Items)
{
<option value="#item.Id"> #item.Name </option>
}
</select>
The idea is when a user selects an option, I want to get the object instead of the key, here is the function:
List<object> ItemContainer = new List<object>();
private void ItemSelected(ChangeEventArgs obj) {
...
ItemContainer.Add(obj);
}
How do I capture the object instead?
#page "/"
<select #onchange="ItemSelected" class="form-select">
<option value="null">Select...</option>
#foreach (var option in options)
{
<option #key="option" value="#option.ID">#option.Value</option>
}
</select>
#code {
private Option option;
private List<Option> options = Enumerable.Range(1, 10).Select(i => new Option { ID = i, Value = $"Option{i}" }).ToList();
private void ItemSelected(ChangeEventArgs args)
{
if (int.TryParse(args.Value.ToString(), out int selectedID))
{
option = options.Where(o => o.ID == selectedID).FirstOrDefault();
Console.WriteLine(option.ID.ToString());
Console.WriteLine(option.Value);
}
}
public class Option
{
#nullable enable
public int? ID { get; set; }
#nullable disable
public string Value { get; set; }
}
}
UPDATE:
Hi, sorry for bothering you but I am stuck a bit on something. How do I avoid Option in my code? Because I already have an Item class private IEnumerable Items { get; set; } = new List(); is there a way to substitute both? thanks
Option is the class name given by me. You can give it whatever name you want. You may define your class like the following instead:
public class ItemDTO
{
#nullable enable
public int? Id { get; set; }
#nullable disable
public string Name{ get; set; }
}
Note: If you're using .Net 6.0, you may remove the #nullable directive
Update:
Don't use Task.Run
Change this:
protected override async Task OnInitializedAsync()
{
await Task.Run(GetItems);
Client = _client.Get(Id);
}
private void GetItems()
{
Items = _item.GetAll();
}
To:
protected override void OnInitialized()
{
Client = _client.Get(Id);
Items = _item.GetAll();
}
Change this:
private IEnumerable<ItemDTO> Items { get; set; } = new List<ItemDTO>();
To:
private IList<ItemDTO> Items { get; set; } = new List<ItemDTO>();
The above changes are rather cosmetics than functional. I've no way to verify this as I only read the code; I do not view and run it in an IDE.
Anyhow, the following code snippet is incorrect and as a result leads to an error:
var option = ItemDTO.Where(o => o.Id ==
selectedID).FirstOrDefault();
The code above is suppose to query the the list of ItemDTO objects, and return a single object whose Id property is equivalent to the value we pass to the method (ItemSelected) in which the code is executed. The list of ItemDTO objects, defined as Items should be used for searching the selected item; that is, you should use:
`Items.Where`
Instead of:
ItemDTO.Where
ItemDTO is a class name or a type...
This is how your code should be:
var option = Items.Where(o => o.Id ==
selectedID).FirstOrDefault();
May God bless your code ;}
You can't directly. ChangeEventArgs returns a string as it's Value object.
You need to do something like this:
#page "/"
<select #onchange=OnSelect >
#foreach (var country in Countries)
{
<option value="#country.Id" selected="#this.IsSelected(country)">#country.Name</option>
}
</select>
<div>
Selected : #this.SelectedCountry
</div>
#code {
private Country? country;
private string SelectedCountry => this.country?.Name ?? "None Selected";
protected override void OnInitialized()
{
// to demo selected is working
this.country = this.Countries[1];
}
private void OnSelect(ChangeEventArgs e)
{
if (int.TryParse(e.Value?.ToString(), out int value))
country = Countries.SingleOrDefault(item => item.Id == value);
}
private bool IsSelected(Country c)
=> c == this.country;
public List<Country> Countries = new List<Country>
{
new Country { Id =44, Name = "UK" },
new Country { Id =61, Name = "France" },
new Country { Id =1, Name = "USA" },
};
public class Country
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
}
Sorry I can't type well now to check the syntax exactly, but maybe something like:
#onchange="(e)=> ItemSelected(Items.Single(i=> i.ID.ToString() == e.Value.ToString()))"
And then
private void ItemSelected(YourItemClass SelectedItem) {}

Populate SelectListItem from generic data type

I have the following code which returns results from a database table comprising of an Id field and a Name field, and transfers it to a list of SelectListItems (this populates a dropdown box in my view.)
var locationTypes = await APIHelper.GetAsync<List<LocationType>>(url);
var items = new List<SelectListItem>();
items.AddRange(locationTypes.Select(locationType =>
{
var item = new SelectListItem();
item.Value = locationType.LocationTypeId.ToString();
item.Text = locationType.Name;
return item;
}));
I am repeating this a lot throughout my application, substituting LocationType for various other things. The item.Value always gets the Id property of the data returned (the Id field is always in the format of {TableName}+"Id"), and the item.Text always gets ".Name" property.
How can I make this generic? I am trying to achieve something like this, although it is syntactically incorrect and may be the incorrect approach:
var myGenericObjects = await APIHelper.GetAsync<List<T>>(url)
var items = new List<SelectListItem>();
items.AddRange(myGenericObjects .Select(myGenericObjects =>
{
var item = new SelectListItem();
item.Value = myGenericObject.Field[0].ToString();
item.Text = myGenericObject.Name;
return item;
}));
You can create a custom extension for a generic list object, then, using reflection retrieve the values that you are wanting to map to the SelectListItem.Text and Name fields. Note I am using "nameof" in order to prevent any confusion or magic string representations of the properties to which I am trying to map.
I did define a default value of "Name" to the namePropertyName parameter. Per your description it sounded like, by convention, most of your DTOs have the property "Name" in them. If that's not the case simply remove the default value that is defined.
There are additional checks that could be made to this extension to prevent NullReference and ArgumentExceptions as well, but for simplicity of the example were left out. Example: Ensuring a value is provided in the idPropertyName and namePropertyName parameters and ensuring those property names exist on the provided generic object prior to conversion.
public static class ListExtensions
{
public static List<SelectListItem> ToSelectList<T>(this List<T> list, string idPropertyName, string namePropertyName = "Name")
where T : class, new()
{
List<SelectListItem> selectListItems = new List<SelectListItem>();
list.ForEach(item =>
{
selectListItems.Add(new SelectListItem
{
Text = item.GetType().GetProperty(namePropertyName).GetValue(item).ToString(),
Value = item.GetType().GetProperty(idPropertyName).GetValue(item).ToString()
});
});
return selectListItems;
}
}
Example Use:
var testList = new List<TestDto>
{
new TestDto { Name = "Test0", TestId = 0 },
new TestDto { Name = "Test1", TestId = 1 },
new TestDto { Name = "Test2", TestId = 2 },
new TestDto { Name = "Test3", TestId = 3 },
new TestDto { Name = "Test4", TestId = 4 },
};
var selectList = testList.ToSelectList(nameof(TestDto.TestId), nameof(TestDto.Name));
Here is the TestDto class for reference:
public class TestDto
{
public int TestId { get; set; }
public string Name { get; set; }
}
Some Prep Work
If you can change the table column names, then use a convention. For example, always name the "Value" column "X", and the "Text" column "Y" (give them better names). Then make all the classes for those tables implement an interface similar to this:
public interface ICustomLookup
{
string X { get; set; }
string Y { get; set; }
}
public class SomeClass : ICustomLookup
{
public string X { get; set; }
public string Y { get; set; }
}
Then an extension method like so:
public static class EnumerableExtension
{
public static SelectList ToSelectList(this IEnumerable<ICustomLookup> items)
{
return new SelectList(items.Select(thisItem => new SelectListItem
{
Text = thisItem.X,
Value = thisItem.Y
}));
}
}
Usage
var items = new List<SomeClass>
{
new SomeClass { X = "XOne", Y = "YOne" },
new SomeClass { X = "XTwo", Y = "YTwo" }
};
SelectList selectList = items.ToSelectList();

Radiobutton acting like a checkbox MVC

With the code below, i can select multiple radio buttons at the same time, that is a problem, a true radio button only works with ONE selected item. How do i re-arrange my code so that it acts like a real radio button and not like a checkbox like the code below?
for (int i = 0; i < Model.RadioButtonItems.Count; i++)
{
<div>
#Html.HiddenFor(m => m.RadioButtonItems[i].RBName)
#Html.LabelFor(l => l.RadioButtonItems[i].RBIsSelected, Model.RadioButtonItems[i].RBName)
#Html.RadioButtonFor(r => r.RadioButtonItems[i].RBIsSelected, true);
</div>
}
The rest of code:
Model:
public class ModelVariables
{
public List<Item> RadioButtonItems { get; set; }
}
public class Item
{
public string RBName { get; set; }
public bool RBIsSelected { get; set; }
}
public static class Repository
{
public static List<Item> RBFetchItems()
{
return new List<Item>()
{
new Item() {RBName = "Metal"},
new Item() {RBName = "Jazz"},
new Item() {RBName = "Trance"}
};
}
}
Controller:
var selectedRBItems = model.RadioButtonItems.Where(x => x.RBIsSelected).Select(x => x.RBName).ToList();
if (model.RadioButtonItems != null && selectedRBItems.Count > 0)
{
ViewBag.RBResults = "Successfully Logged Pressed RB's!";
}
else
{
ViewBag.RBResults = "You must select a radio button!";
}
Summary: this code let's you select multiple radiobuttons, i DONT want that, i want only one possible selection out of many options.
Each radio button has a different name attribute so they are not grouped. Your model needs a property to bind the selected value to, and a collection of items for the options
public class ModelVariables
{
[Required(ErrorMessage = "...")]
public string SelectedValue { get; set; }
public List<string> Options { get; set; }
}
and in the GET method
var model = new ModelVariables()
{
Options = new List<string>() { "Metal", "Jazz", "Trance" },
SelectedValue = ? // set this if you want one of the buttons initially selected
};
return View(model);
and in the view
foreach (var option in Model.Options)
{
<label>
#Html.RadionButtonFor(m => m.SelectedValue, option, new { id = "" })
<span>#option</span>
</label>
}
// add the following if you do not set an initial value in the GET method
#Html.ValidationMessageFor(m => m.SelectedValue)

MVC5 Razor html.dropdownlistfor set selected when value is in array

I'm developing an ASP.NET MVC 5 application, with C# and .NET Framework 4.6.1.
I have this View:
#model MyProject.Web.API.Models.AggregationLevelConfViewModel
[...]
#Html.DropDownListFor(m => m.Configurations[0].HelperCodeType, (SelectList)Model.HelperCodeTypeItems, new { id = "Configurations[0].HelperCodeType" })
The ViewModel is:
public class AggregationLevelConfViewModel
{
private readonly List<GenericIdNameType> codeTypes;
private readonly List<GenericIdNameType> helperCodeTypes;
public IEnumerable<SelectListItem> CodeTypeItems
{
get { return new SelectList(codeTypes, "Id", "Name"); }
}
public IEnumerable<SelectListItem> HelperCodeTypeItems
{
get { return new SelectList(helperCodeTypes, "Id", "Name"); }
}
public int ProductionOrderId { get; set; }
public string ProductionOrderName { get; set; }
public IList<Models.AggregationLevelConfiguration> Configurations { get; set; }
public AggregationLevelConfViewModel()
{
// Load CodeTypes to show it as a DropDownList
byte[] values = (byte[])Enum.GetValues(typeof(CodeTypes));
codeTypes = new List<GenericIdNameType>();
helperCodeTypes = new List<GenericIdNameType>();
for (int i = 0; i < values.Length; i++)
{
GenericIdNameType cType = new GenericIdNameType()
{
Id = values[i].ToString(),
Name = EnumHelper.GetDescription((CodeTypes)values[i])
};
if (((CodeTypes)values[i]) != CodeTypes.NotUsed)
codeTypes.Add(cType);
helperCodeTypes.Add(cType);
}
}
}
And Models.AggregationLevelConfiguration is:
public class AggregationLevelConfiguration
{
public byte AggregationLevelConfigurationId { get; set; }
public int ProductionOrderId { get; set; }
public string Name { get; set; }
public byte CodeType { get; set; }
public byte HelperCodeType { get; set; }
public int PkgRatio { get; set; }
public int RemainingCodes { get; set; }
}
I need to set selected value in these properties:
public IEnumerable<SelectListItem> CodeTypeItems
{
get { return new SelectList(codeTypes, "Id", "Name"); }
}
public IEnumerable<SelectListItem> HelperCodeTypeItems
{
get { return new SelectList(helperCodeTypes, "Id", "Name"); }
}
But I can't set it in new SelectList(codeTypes, "Id", "Name"); or new SelectList(helperCodeTypes, "Id", "Name"); because the selected value are in Configurations array: fields AggregationLevelConfiguration.CodeType and AggregationLevelConfiguration.HelperCodeType.
I think I have to set selected value in the View, but I don't know how to do it.
How can I set the selected values?
Unfortunately #Html.DropDownListFor() behaves a little differently than other helpers when rendering controls in a loop. This has been previously reported as an issue on CodePlex (not sure if its a bug or just a limitation)
The are 2 option to solve this to ensure the correct option is selected based on the model property
Option 1 (using an EditorTemplate)
Create a custom EditorTemplate for the type in the collection. Create a partial in /Views/Shared/EditorTemplates/AggregationLevelConfiguration.cshtml (note the name must match the name of the type
#model yourAssembly.AggregationLevelConfiguration
#Html.DropDownListFor(m => m.HelperCodeType, (SelectList)ViewData["CodeTypeItems"])
.... // other properties of AggregationLevelConfiguration
and then in the main view, pass the SelectList to the EditorTemplate as additionalViewData
#using (Html.BeginForm())
{
...
#Html.EditorFor(m => m.Configurations , new { CodeTypeItems = Model.CodeTypeItems })
...
Option 2 (generate a new SelectList in each iteration and set the selectedValue)
In this option your property CodeTypeItems should to be IEnumerable<GenericIdNameType>, not a SelectList (or just make codeTypes a public property). Then in the main view
#Html.DropDownListFor(m => m.Configurations[0].HelperCodeType, new SelectList(Model.CodeTypeItems, "Id", "Name", Model.Configurations[0].HelperCodeType)
Side note: there is no need to use new { id = "Configurations[0].HelperCodeType" - the DropDownListFor() method already generated that id attribute
I wrote this class to overcome an issue I was having with selecting an option in an html select list. I hope it helps someone.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
namespace Login_page.Models
{
public class HTMLSelect
{
public string id { get; set; }
public IEnumerable<string> #class { get; set; }
public string name { get; set; }
public Boolean required { get; set; }
public string size { get; set; }
public IEnumerable<SelectOption> SelectOptions { get; set; }
public HTMLSelect(IEnumerable<SelectOption> options)
{
}
public HTMLSelect(string id, string name)
{
this.id = id;
this.name = name;
}
public HTMLSelect(string id, string name, bool required, IEnumerable<SelectOption> options)
{
this.id = id;
this.name = name;
this.required = required;
}
private string BuildOpeningTag()
{
StringBuilder text = new StringBuilder();
text.Append("<select");
text.Append(this.id != null ? " id=" + '"' + this.id + '"' : "");
text.Append(this.name != null ? " name=" + '"' + this.name + '"' : "");
text.Append(">");
return text.ToString();
}
public string GenerateSelect(IEnumerable<SelectOption> options)
{
StringBuilder selectElement = new StringBuilder();
selectElement.Append(this.BuildOpeningTag());
foreach (SelectOption option in options)
{
StringBuilder text = new StringBuilder();
text.Append("\t");
text.Append("<option value=" + '"' + option.Value + '"');
text.Append(option.Selected != false ? " selected=" + '"' + "selected" + '"' + ">" : ">");
text.Append(option.Text);
text.Append("</option>");
selectElement.Append(text.ToString());
}
selectElement.Append("</select");
return selectElement.ToString();
}
}
public class SelectOption
{
public string Text { get; set; }
public Boolean Selected { get; set; }
public string Value { get; set; }
}
}
And
public IEnumerable<SelectOption> getOrderTypes()
{
List<SelectOption> orderTypes = new List<SelectOption>();
if (this.orderType == "OptionText")
{
orderTypes.Add(new SelectOption() { Value = "1", Text = "OptionText", Selected = true });
} else
{
orderTypes.Add(new SelectOption() { Value = "2", Text = "OptionText2" });
}
}
And to use it:
#{
Login_page.Models.HTMLSelect selectElement = new Login_page.Models.HTMLSelect("order-types", "order-types");
}
#Html.Raw(selectElement.GenerateSelect(Model.getOrderTypes()));
I leave this in case it helps someone else. I had a very similar problem and none of the answers helped.
We had in a view this line at the top:
IEnumerable<SelectListItem> exitFromTrustDeed = (ViewData["ExitFromTrustDeed"] as IEnumerable<string>).Select(e => new SelectListItem() {
Value = e,
Text = e,
Selected = Model.ExitFromTrustDeed == e
});
and then below in the view:
#Html.DropDownListFor(m => m.ExitFromTrustDeed, exitFromTrustDeed, new { #class = "form-control" })
We had a property in my ViewData with the same name as the selector for the lambda expression and for some reason that makes the dropdown to be rendered without any option selected.
We changed the name in ViewData to ViewData["ExitFromTrustDeed2"] and that made it work as expected.
Weird though.

DropDownList SelectList SelectedValue issue [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How can I get this ASP.NET MVC SelectList to work?
What the hell is it? Is there some kind of a bug in DropDownList of MVC3?
SelectedValue doesn't show up as actually selected in the markup.
I am trying different approaches, nothing works.
public class SessionCategory
{
public int Id { get; set; }
public string Name { get; set; }
}
public static IEnumerable<SessionCategory> Categories
{
get
{
var _dal = new DataLayer();
return _dal.GetSesionCategories();
}
}
#{
var cats = Infrastructure.ViewModels.Session.Categories;
var sl = new SelectList(cats, "Id", "Name",2);
}
#Html.DropDownList("categories", sl);
Try the following:
Model:
public class MyViewModel
{
public int CategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
Controller:
public ActionResult Foo()
{
var cats = _dal.GetSesionCategories();
var model = new MyViewModel
{
// Preselect the category with id 2
CategoryId = 2,
// Ensure that cats has an item with id = 2
Categories = cats.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
})
};
}
View:
#Html.DropDownListFor(
x => x.CategoryId,
new SelectList(Model.Categories, "Value", "Text")
)
I think you need to make the selected value a string. There's also some value in using extension methods as detailed here.

Categories

Resources