I have something like the following in an ASP.NET MVC application:
IEnumerable<string> list = GetTheValues();
var selectList = new SelectList(list, "SelectedValue");
And even thought the selected value is defined, it is not being selected on the view. I have this feeling I'm missing something here, so if anyone can put me out my misery!
I know I can use an annoymous type to supply the key and value, but I would rather not add the additional code if I didn't have to.
EDIT: This problem has been fixed by ASP.NET MVC RTM.
If you're just trying to to map an IEnumerable<string> to SelectList you can do it inline like this:
new SelectList(MyIEnumerablesStrings.Select(x=>new KeyValuePair<string,string>(x,x)), "Key", "Value");
Try this instead:
IDictionary<string,string> list = GetTheValues();
var selectList = new SelectList(list, "Key", "Value", "SelectedValue");
SelectList (at least in Preview 5) is not clever enough to see that elements of IEnumerable are value type and so it should use the item for both value and text. Instead it sets the value of each item to "null" or something like that. That's why the selected value has no effect.
Take a look at this: ASP.NET MVC SelectList selectedValue Gotcha
This is as good explanation of what is going on as any.
Try this
ViewBag.Items = list.Select(x => new SelectListItem()
{
Text = x.ToString()
});
Related
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();
I have this in my controller:
[Route("Checkout")]
public ActionResult Checkout()
{
var sb = new ShoppingBagViewModel();
sb.DestinationCountry = "Netherlands"; // I hoped that this was sufficient
sb.CountriesSl.Single(c => c.Text.Equals("Netherlands", StringComparison.InvariantCultureIgnoreCase)).Selected = true;
return View(sb);
}
Quick watch in Visual Studio confirmed that the CountriesSl (which is of type List<SelectListItem>) has a selected value. (netherlands)
This is my razor view:
#Html.DropDownListFor(m => m.DestinationCountry, Model.CountriesSl)
DestinationCountry is also a string prop in my viewmodel.
I know that there are a lot of similar questions, but I have looked at a lot of them and I just do not see it.
I also tried:
#Html.DropDownListFor(m => Model.DestinationCountry, Model.CountriesSl)
Please do not just give me the answer, but also explain what my mistake is.
edit to make clear what the problem is: I get a nice option list in my razor view, but there is no item "selected" just the first one. When I look at the generated html, there is no selected item too.
edit for Ric
public List<SelectListItem> CountriesSl
{
get
{
List<SelectListItem> _countries = HttpContext.Current.Cache["slCountries"] as List<SelectListItem>;
if (_countries == null)
{
_countries = new List<SelectListItem>();
foreach (string s in System.IO.File.ReadLines(System.Web.Hosting.HostingEnvironment.MapPath("~/tmpwrite/countries.csv")))
{
var tmp = s.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
_countries.Add(new SelectListItem() { Text = tmp[1], Value = tmp[0], Selected = false });
}
HttpContext.Current.Cache.Add("slCountries", _countries.OrderBy(c => c.Text).ToList(), null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(24, 0, 0), System.Web.Caching.CacheItemPriority.Normal, null);
}
return _countries;
}
}
DropDownListFor tries to automatically match the value of the receiving property in the provided enumeration. I also had problems with this in the beginning.
Instead provide any list of entities in the viewmodel. I usually use something like IDictionary<int, string>. Then create the dropdown like this:
Html.DropDownListFor(m=>m.DestinationCountry, new SelectList(Model.Countries, "Key", "Value"))
Then the SelectList will automagically set the correct option where its Key matches DestinationCoutry.
I have s simple dropdown which is rendered with:
#Html.DropDownListFor(m => m.Request.Value, new SelectList(items, "Value", "Text", selectedElement), new {})
where Model.Request.Value is of type int and has the value set to -1.
items is build like:
var items = new List<SelectListItem<int>>();
items.Add(new SelectListItem<int>{Text = "10", Value = 10});
items.Add(new SelectListItem<int>{Text = "25", Value = 25});
items.Add(new SelectListItem<int>{Text = "100", Value = 100});
items.Add(new SelectListItem<int>{Text = "All", Value = -1});
The value of selectedElementis 25, which is of type int. However, it always renders the select with All selected, which means value = -1.
Why? And why is there a value selectedElement which get's overridden no matter what?
Your strongly binding to a property in your model, so its the value of the property that determines what is selected. That's how model binding works. If you want "All" to be selected, set the value of Request.Value = -1
The 4th parameter of the SelectList constructor is ignored when binding to a property. The only time it is respected is if you were to use something like #Html.DropDownList("NotAPropertyOfMyModel, new (SelectList(...
Side note: items is IEnumerable<SelectListItem> (which is what the DropDownListFor() method requires) so creating a new IEnumerable<SelectListItem> (which is what SelectList is) is just pointless extra overhead. Your view should be just
#Html.DropDownListFor(m => m.Request.Value, items)
DropDownListFor uses the value of lambda expression to select the item in the dropdown list rather than the last argument of the SelectList constructor.
I believe that the following link includes sample code that should be able to help you:
MVC DropDownList SelectedValue not displaying correctly
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.
I had to change on my lines of code around. I before had something like this
// this is in a static method.
List<string> mySTring = new List<string>();
mySTring.add("one");
mySTring.add("two");
However on one of my pages I have a dropdownlist that does not require the field "two" so instead of writing duplicate code all I did was
myString.remove("two");
Now I need to change my list to a List<SelectListItem> myList = new List<SelectListItem>();
So I have it now looking like this:
List<SelectListItem> myList = new List<SelectListItem>()
{
new SelectListItem() { Text = "one", Value = "one"},
new SelectListItem() { Text = "two", Value = "two"},
};
So now how do I remove the selectListItem that contains "two"? I know I probably could use remove by index. But I might add to list in the future so I don't want to start hunting down and changing it if the index changes.
Thanks
List<T> is, by default, going to be comparing object references (unless SelectListItem implements a custom equality method). So unless you still have a reference to the second item around, you are going to have to get it either by reference, or by finding the desired item:
var item = myList.First(x=>x.Value == "two");
myList.Remove(item);
Index may be easier...
You could use the RemovalAll method:
myList.RemoveAll(i => i.Text == "two");
Obviously this will get rid of all the items whose "Text" property is "two", but since you're using it in a ComboBox I'm assuming you'll only have one item for each "Text" value.
we can make mouse selection over the autocomplete div by adding this following code
into the jquery autocomplete function
here i have used the id name as Requiredid
$("#Requiredid").autocomplete({focus:function(e,ui) {
document.getElementById('Requiredid').value = ui.item.label;
document.getElementById('hdnValue').value = ui.item.id;//If You need this value you //can add this line
}});