Set default for dropdownlist in view - c#

I have a dropdownlist that I want to set a default value for but the way I have it set up does not work with all the examples I have seen on the web. Here is my controller code for getting the string:
ViewBag.RoleId = new SelectList(db.Roles, "RoleId", "RoleDescription");
Then here is the code of my dropdownlist in the view:
#Html.DropDownList("RoleId", null, "Select Role", htmlAttributes: new { #class = "form-control" })
I want to set that dropdownlist to be defaulted to a User Role but I cannot figure it out.
Here is the code for my roleID in my model trying to set the default value:
[Display(Name = "Role")]
[Required]
[DefaultValue('B2323674-45DC-45E7-91D2-E635CF63C04A')]
[ForeignKey("Role")]
public Guid RoleID { get; set; }
problem is I am getting an error on the Guid Default saying that it is too long for a string literal.

You can use this overload of the SelectList that accepts default value:
ViewBag.RoleId = new SelectList(db.Roles, "RoleId", "RoleDescription", selectedValue);
Where selectedValue is an object of whatever type is in your list.
Initializes a new instance of the SelectList class by using the
specified items for the list, the data value field, the data text
field, and a selected value.
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField,
object selectedValue
)
So in your case:
ViewBag.RoleId = new SelectList(db.Roles, "RoleId", "RoleDescription", "B2323674-45DC-45E7-91D2-E635CF63C04A");
more info.
Also there's another solution that personally I recommand you that, Using jQuery in view for selection for example the first item of the drop down list:
$("#target").val($("#target option:first").val());

The problem is that your ViewBag property and your model property are named the same. When Razor renders the values for your fields it uses the data from ModelState. ModelState is composed from values from ViewBag, ViewData, Request and Model as a last resort. In other words, since the name of the ViewBag property and Model property are the same, you're essentially saying that the selected value of RoleId is the entire SelectList, which obviously is not what you want.
The simplest solution is to simply name your ViewBag property something else, like ViewBag.RoleIdChoices. Then, you'll be fine.

There's a couple things going on here.
You won't be able to bind a dropDownList to a ViewBag collection "Extension methods cannot be dynamically dispatched." Meaning, you need to include your SelectList into your Model.
You can set a SelectedValue in your SelectList
ViewBag.RoleId = new SelectList(db.Roles, "RoleId", "RoleDescription", <DefaultRoleObj>);
You need to include the reference to you selectList in your DropDownList
#Html.DropDownList("RoleId", <Model.SelectList>)

Related

Putting data from two tabels in one ViewData

I'm trying to put data form two tabels (AcademicDegrees, Lecturers) conneted by one to many relation into one ViewData to generate options to field (with label and id as value). It shoud be somthing like this where id are used as values nad other field as label.
ViewData["ClassroomsId"] = new SelectList(_context.Classroom, "ClassroomsID", "Number");
When all the date for field was in one table I used getter form field to get it.
[NotMapped]
public string toStringVar => FirstName + " " + LastName;
When I added tabel with academic degrees I moved to different solution.
var lecturers = _context.Lecturer;
var degree = _context.AcademicDegrees;
var lecturersList = new List<SelectListItem>();
foreach (Lecturers l in lecturers)
{
_context.AcademicDegrees.Where(d => d.AcademicDegreeId == l.AcademicDegreesId).Load();
foreach(AcademicDegrees d in degree)
{
lecturersList.Add(new SelectListItem(
$"{d.Name} {l.FirstName} {l.LastName}", l.LecturersID.ToString()
));
}
}
ViewData["LecturersId"] = new SelectList(lecturersList);
The problem is that it isn't interpreted as I want it to be.
I also can't put it directly in to SelectList because it doesn't have empty constructor or add method. Is there any other way to implement a SelectList?
In my opinion, it is like redundant work as you have the IEnumerable<SelectListItem> instance which can be used to build the select option.
And you pass IEnumerable<SelectListItem> instance to create the SelectList instance.
Would suggest to pass IEnumerable<SelectListItem> value to ViewData.
Solution for IEnumerable<SelectListItem>
Controller
ViewData["LecturersId"] = lecturersList;
View
#Html.DropDownListFor(model => model./*YourProperty*/, (IEnumerable<SelectListItem>)ViewData["LecturersId"])
Updated
Since you are using ASP.NET Core MVC, with tag helper:
<select asp-for="/*YourProperty*/"
asp-items="#((IEnumerable<SelectListItem>)ViewData["LecturersId"]))">
</select>
Solution for SelectList
If you are keen on the SelectList, make sure that you have provided the dataValueField and dataTextField according to this constructor
public SelectList (System.Collections.IEnumerable items, string dataValueField, string dataTextField);
as below:
ViewData["LecturersId"] = new SelectList(lecturersList, "Value", "Text");
Besides, the query part would be suggested to optimize by joining both tables as below:
var lecturersList = (from a in _context.Lecturer
join b in _context.AcademicDegrees on a.AcademicDegreeId equals b.AcademicDegreeId
select new SelectListItem($"{b.Name} {a.FirstName} {a.LastName}", a.LecturersID.ToString())
).ToList();

Convert List of Enums to a SelectList and maintain display?

We have a view that is driven by a List of options. Depending on the initial conditions, a DropDownList is created with choices for the user's next step. This list is populated with choices from a larger list of options encased within a custom Enumeration.
So we have an Enum like so:
public enum ChangeMode
{
[Display(Name ="Please Select")] InitialState,
[Display(Name = "Change A Thing")] ChangeThing,
//...
[Display(Name = "Do a Dance")] DoADance,
FinishedSuccess,
FinishedFailure
}
And in the controller for the view, we build a List that contains all the valid options for the user, which is NEVER the full list.
if( /*Irrelevant determining characteristic*/ )
{//Valid choices for this option
model.ValidModes = new List<ChangeMode> { ChangeMode.InitialState, ChangeMode.ChangeThing};
}
We then create a DropDownList in the view, based on the model's list of ChangeModes
#Html.DropDownListFor(m => Model.AlterMethod, new SelectList(Model.ValidModes))
All of this is working just fine, except that the generated DDL does not include the user-friendly Name that each mode is assigned, instead showing the Enum's developer-readable value ('InitialState', for example). How do I change this to have the View correctly render the dropdownlist such that it uses the Display(Name) as the Text for the DDL?
You'll need to get the values from your Enum attributes. To do this, you need a helper method that will return the attribute.
here is a helper method to access Enum attributes:
public T GetAttribute<T>(Enum _enum) where T : Attribute
{
return
(T)_enum.GetType()
.GetField(Enum.GetName(_enum.GetType(), _enum))
.GetCustomAttribute(typeof(T));
}
Usage :
var name = GetAttribute<DisplayAttribute>(ChangeMode.InitialState).Name;
ASP.NET Core ships with a helper for generating a SelectListItem for
any enum.
This means that if you have an enum of the TEnum type, you can generate the available options in your
View using asp-items="Html.GetEnumSelectList<TEnum>()".
Change:
#Html.DropDownListFor(m => Model.AlterMethod, new SelectList(Model.ValidModes))
To:
<select asp-for="AlterMethod" asp-items="Html.GetEnumSelectList<Enums.ChangeMode>()"></select>
Or if you only want the Values from ValidModes:
<select asp-for="AlterMethod" asp-items="Html.GetEnumSelectList(typeof(Model.ValidModes))"></select>

Selected property on SelectListItem not being set by SelectList constructor

I'm creating a SelectList to pass to a Html.DropDownList, but the correct value doesn't seem to be populating
var x = new SelectList(new[] {
new SelectListItem() { Value="1", Text="Vanilla"},
new SelectListItem() { Value="2", Text="Chocolate"},
new SelectListItem() { Value="3", Text="Strawberry"}
}, "Value", "Text", "2");
SelectList should take a constructor that takes in the selectedValue:
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField,
object selectedValue
)
But this only sets the SelectedValue on the entire collection. The individual SelectListItems haven't been set as Selected
Do I need to iterate over them individually and set selected for each as in this question?
The Selected property is being set by the SelectList constructor. The image you have shown is for the items argument (i.e the collection of SelectListItem that you passing to the method), not the result of calling the method.
The constructor does not modify the collection passed to it, it creates a new IEnumerable<SelectListItem>, and if you inspect the value of var x, then you will see that the 2nd SelectListItem (the one with Value = "2") will have its Selected property set to true.
However, the purpose of the SelectListItem class is for use in one of the HtmlHelper methods that generates a <select> (DropDownList(), DropDownListFor(), ListBox() and ListBoxFor() methods) which accept an IEnumerable<SelectListItem> as either the 1st or 2nd argument.
Unless you specifically not binding to a model property (e.g. #Html.DropDownList("NotAModelProperty", Model.YourSelectList)), then setting the Selected property is ignored because the method sets the selected option based on the value of the property your binding to (refer How to set “selectedValue” in DropDownListFor Html helper for more detail), therefore creating a new IEnumerable<SelectListItem> from the first one by using new SelectList(...) is pointless extra overhead.
The reason for using the SelectList constructor is to create an IEnumerable<SelectListItem> from an existing collection of objects, for example
IEnumerable<SelectListItem> options = new SelectList(db.Flavors, "ID", "Name")
which would get the records from the Flavors table, and set the Value based on its ID property, and the Text based on its Name property. It just provides an alternative to using (say)
IEnumerable<SelectListItem> options = db.Flavors.Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.Name
});

DropDownList without value at the PostBack

I have created a DropDownList which is initialized from code behind like that :
Code Behind :
List<SelectListItem> ddlIsActivated = new List<SelectListItem>
{
new SelectListItem
{
Text = "Activated",
Value = "0"
},
new SelectListItem
{
Text = "Not activated",
Value = "1"
}
};
ViewBag.ddlIsActivated = ddlIsActivated;
View :
<div class="row">
<div class="form-group col-xs-3">
#Html.DropDownList("IsActivated", ViewBag.ddlIsActivated as List<SelectListItem>, "Default")
</div>
</div>
When I click directly on the search button after the load, the DropDownList has "Default" as the first item and my URL looks like that :
http://localhost:51817/Log?SearchString=&IsActivated=
Is it possible to specify that all parameters with an empty value might not be passed on the URL ?
In case of the DropDownList, is it possible to avoid the param "IsActivated" when the "Default" is Selected ?
Sure one way is when the submit button is clicked or activated, you set the fields that are the default value to disabled. then they don't go in the post.
Example of using jQuery onsubmit:
How to use jQuery to onsubmit and check if the value is 2 - 5 characters?
You can try having a separate viewmodel, with properties for the list of options and the selected option. In the GET request action method, you can populate this list and render the view, and in the POST action method, you can exclude this property during model binding, so that only the selected item property will get bound. Thus, you don't need ViewBag or routeValues or querystring parameters, and your URL will always look clean.
EDIT:
This is how you might do it.
public class ViewModel
{
public int SelectedId { get; set; }
public Dictionary<int,string> OptionList { get; set; }
}
And then in your view,
#Html.DropDownListFor(model => model.SelectedId, new SelectList(Model.OptionList, "Key", "Value"), null, null)
In your GET action method,
Dictionary<int,string> OptionList = GetOptionList(); // Populate from DB
return View(new ViewModel { OptionList = OptionList });
Also, remember to [Bind(Exclude="OptionList")] in your POST action method.

MVC4 - Setting Initially Selected Item in DropDownList

I am passing in a list of objects to my View via a model
#model MyModel.ObjectViewModel
I am new to MVC and am trying to set the initially selected item of a dropdownlist in my view (modelled after an Edit).
I am then binding this to a drop down list as follows
<label for="ddlObjects">Select Object</label>
#Html.DropDownList("ddlObjects", Model.AllObjectsSelectList, Model.Object.ObjectName)
The above does make the drop down list have the correct object selected initially, but I discovered it is only in the form of text. The real object isn't chosen and as such the value isn't used. How can I have a list of items, say, "Object1" "Object2", etc and have the default be a specific one?
When I'm passing through the item I only know the text value (the name that appears in the drop down list) of the item, I don't know it's inner value so I can't really use SelectListItem {Text = "X", Value= "Y"}
I have searched here and through google, and there are options for setting the intially selected value, however they are using methods like #Html.DropDownList for which doesn't seem to let me specify a control name, and in my controller I specifically reference the name of the control.
My work around wasn't pretty, but it could be easily refactored to be much nicer. It will just be a case of some effort which at present I don't have time for - but I will in the next week or so.
I created a method in my controller which I pass in my list of items (selectList, which you would think would work anyway... but it doesn't) then I work out which is the object I require and set the Selected property to true.
private List<SelectListItem> GetListOfObjectTypes(SelectList selectList, string objectTypeName, string objectTypeId)
{
List<SelectListItem> items = new List<SelectListItem>();
foreach (METAObjectType item in selectList.Items)
{
bool isSelected = false;
if (item.Name == objectTypeName)
{
isSelected = true;
}
items.Add(new SelectListItem {Selected= isSelected, Text=item.Name, Value=item.ObjectTypeId.ToString()});
}
return items;
}
I then just pass this through to my View and set it as the list in the #Html.DropDownList and it will now select the correct item by default.

Categories