I am using hardcoded string values for dropdownlist to the view , and passing the selected value from database , where 0 = pending , 1 = complete and 3 = awaiting, below is the code for view and controller:
var paymentStatus = new[] { "Pending", "Complete", "AwaitingPayment" };
ViewData["StatusID"] = new SelectList(paymentStatus, "Value", "Text", booking.StatusID);
<tr><td>Status</td><td><%: Html.DropDownListFor(m => m.StatusID, ViewData["StatusID"] as SelectList)%></td></tr>
It comes up with the error :
DataBinding: 'System.String' does not contain a property with the name 'Value'.
The problem with your example is that you are passing a string array into the SelectList and then telling the SelectList to use the Value and Text properties (which a string does not have). You should probably create a class for this:
public class Status {
public int Id { get; set; }
public string Text { get; set; }
}
var statusTypes = new List<Status> {
new Status { Id = 1, Text = "Pending" },
new Status { Id = 2, Text = "Complete" },
new Status { Id = 3, Text = "AwaitingPayment" }
};
Better yet, create a repository for this data:
var statusTypes = statusRepository.GetStatusTypes();
Pass this into your SelectList:
SelectList statusList = new SelectList(statusTypes, "Id", "Text", booking.StatusID);
// return this in a ViewModel or use ViewData like you are now:
ViewData["Status"] = statusList;
return View(statusList);
Please use view models:
var paymentStatuses = new[]
{
new SelectListItem { Value = "0", Text = "Pending" },
new SelectListItem { Value = "1", Text = "Complete" },
new SelectListItem { Value = "3", Text = "AwaitingPayment" },
};
var model = new SomeViewModel
{
StatusID = booking.StatusID,
Statuses = new SelectList(paymentStatuses, "Value", "Text")
}
return View(model);
and then:
<tr>
<td>
Status
</td>
<td>
<%= Html.DropDownListFor(m => m.StatusID, Model.Statuses) %>
</td>
</tr>
or if you insist on this ViewData (I don't recommend it, especially as you already have a view model):
var paymentStatuses = new[]
{
new SelectListItem { Value = "0", Text = "Pending" },
new SelectListItem { Value = "1", Text = "Complete" },
new SelectListItem { Value = "3", Text = "AwaitingPayment" },
};
ViewData["Statuses"] = new SelectList(paymentStatuses, "Value", "Text");
var model = new SomeViewModel
{
StatusID = booking.StatusID
}
return View(model);
and in the view:
<tr>
<td>
Status
</td>
<td>
<%= Html.DropDownListFor(m => m.StatusID, ViewData["Statuses"] as SelectList) %>
</td>
</tr>
The error shows it is unable to Fine "Value" , you have to do something like
new SelectList(paymentStatus, booking.Status, "Text", booking.StatusID)
bookin.Status will be the any text property of booking. hope this help
Related
I realize there are tons of questions on SO about this particular issue, however none of the answers that I've already found are doing quite what I am doing.
View Model
public FreightDiscountViewModel()
{
Sign = new List<SelectListItem>();
States = new List<SelectListItem>();
FreightDiscounts = new List<FreightDiscountModel>();
PopSign();
PopStates();
}
public List<FreightDiscountModel> FreightDiscounts { get; set; }
public List<SelectListItem> States { get; set; }
public List<SelectListItem> Sign { get; set; }
private void PopSign ()
{
Sign.Add(new SelectListItem { Text = "-", Value = "-" });
Sign.Add(new SelectListItem { Text = "+", Value = "+" });
}
private void PopStates ()
{
States.Add(new SelectListItem { Value = "AL", Text = "Alabama" });
States.Add(new SelectListItem { Value = "AK", Text = "Alaska" });
States.Add(new SelectListItem { Value = "AZ", Text = "Arizona" });
States.Add(new SelectListItem { Value = "AR", Text = "Arkansas" });
States.Add(new SelectListItem { Value = "CA", Text = "California" });
States.Add(new SelectListItem { Value = "CO", Text = "Colorado" });
}
}
View
#for (var i = 0; i < Model.FreightDiscounts.Count; i++ )
{
<tr>
<td>#Html.DropDownListFor(x => x.FreightDiscounts[i].State, Model.States, new { #class = "form-control" })</td>
</tr>
}
I am populating my FreightDiscounts list in my view model without issue, and right now for testing, I only have 1 state being returned, Alaska. So the 1 record that being populated in that list has the following info
AK,
US,
50,
0,
+
My question is that when the view loads, the state dropdown for the 1 record is set to Alabama (AL), and not Alaska like I would expect. Does anyone see anything obvious I am missing?\
Edit
JamieD77's answer fixed my problem. I changed my View to the following.
<td>
#Html.DropDownListFor(x => x.FreightDiscounts[i].State,
new SelectList(Model.DStates, "key", "value", Model.FreightDiscounts[i].State), new { #class = "form-control" })
</td>
And I changed my View Model to the following
public Dictionary<String, String> DStates { get; set; }
DStates.Add("AL","Alabama" );
DStates.Add("AK","Alaska" );
try using a SelectList and setting the selected item when you build the dropdownlistfor
#Html.DropDownListFor(x => x.FreightDiscounts[i].State,
new SelectList(Model.States, "Value", "Text", x.FreightDiscounts[i].State),
new { #class = "form-control" })
Possibly because your Text and Value fields are reversed?
Edit: OP has updated his code, they originally were reversed.
I have an action that retrieves data and sends it to a view. In a view I have two dropdown menus.
First drop down shows salutation (such as "Mr.", "Ms.", etc.) and does not select value I sent for some reason. The other dropdown shows language list and correctly selects value I sent to the view. The relevant code in view is shown below.
#Html.DropDownListFor(model => model.Salutation, ViewBag.salutation as IEnumerable<SelectListItem>)
#Html.DropDownListFor(model => model.Language, ViewBag.languages as IEnumerable<SelectListItem>)
In the controller I have the following code to get the dropdown data.
ViewBag.salutation = new List<SelectListItem>() {
new SelectListItem() { Text = "", Value = "" },
new SelectListItem() { Text = "Mr.", Value = "Mr." },
new SelectListItem() { Text = "Ms.", Value = "Ms." },
new SelectListItem() { Text = "Mrs.", Value = "Mrs." }
};
and
var languages = (from l in db.Languages.ToList()
select new SelectListItem()
{
Text = l.Language,
Value = l.LanguageId.ToString()
}).ToList();
languages.Insert(0, new SelectListItem() { Text = "", Value = "" });
ViewBag.languages = languages;
The only difference I could think of is that the languages dropdown has an integer as value, whereas salutation dropdown has text as value. Is this why the salutation dropdown doesn't work? I know I could go through each salutation List<SelectListItem> item and set Selected property based on the value I retrieved from database. But I was hoping there would be a cleaner way to do this.
Any ideas?
Thanks
UPDATE
I decided to do what I did for another project.
IList<SelectListItem> _salutation = new List<SelectListItem>()
{
new SelectListItem() { Value = "", Text = "" },
new SelectListItem() { Value = "Mr.", Text = "Mr." },
new SelectListItem() { Value = "Ms.", Text = "Ms." },
new SelectListItem() { Value = "Mrs.", Text = "Mrs." }
};
// I could put the following in the declaration above, but for testing purposes it's in foreach loop.
foreach (var item in _salutation)
{
// compare to what's retrieved from database
item.Selected = item.Value == _viewData.Salutation;
}
ViewBag.salutation = _salutation;
After foreach loop I output .Value, .Selected property of each item in _salutation and I get all the correct values with one item being selected. Inside the view I did the following.
#foreach (var item in ViewBag.salutation as IEnumerable<SelectListItem>)
{
<b>#item.Value : #item.Text : #item.Selected</b><br />
}
All the correct Text/Values come up but none are Selected! This happens if I output the values after I execute #Html.DropDownListFor(). If I output the ViewBag.salutation before the html helper the correct value is selected.
SOLUTION
I found the following article useful: DropDownListFor with ASP.NET MVC.
Instead of using ViewBag I added the following to the ViewModel. (Showing the part for salutations drop down.)
public class TheViewModel
{
private IList<string> _salutations = new List<string>() { "", "Mr.", "Ms.", "Mrs." };
public IEnumerable<SelectListItem> SalutationItems
{
get
{
var salutations = _salutations.Select(s => new SelectListItem { Value = s, Text= s });
return salutations;
}
}
// The rest of the ViewModel
}
And in the View I have the following.
#Html.DropDownListFor(model => model.Salutation, Model.SalutationItems)
Instead of just supplying the list to the DropDownListFor helper you could provide it a SelectList. The SelectList constructor takes the list and allows you to explicitly set the selected value as well as an overload that lets you specify the Text and Value fields.
#Html.DropDownListFor(model => model.Salutation,
new SelectList(ViewBag.salutation as IEnumerable<SelectListItem>,
"Value", "Text", Model.Salutation))
Try this,
#Html.DropDownListFor(m =>m.DDCountryModel,IEnumerable<SelectListItem>)ViewBag.salutation)
#Html.DropDownListFor(model => model.Language, IEnumerable<SelectListItem>)ViewBag.languages)
Your Model should be like this,
public class Model
{
public IEnumerable<SelectListItem> DDCountryModel{ get; set; }
public IEnumerable<SelectListItem> Language{ get; set; }
}
So I have the following (pseudo code):
string selectedvalud = "C";
List<SelectListItem> list= new List<SelectListItem>();
foreach(var item in mymodelinstance.Codes){
list.Add(new SelectListItem { Text = item.Name, Value = item.Id.Tostring(), Selected = item.Id.ToString() == selectedvalue ? true : false });
}
ViewBag.ListOfCodes = list;
on my view:
<%: Html.DropDownList("Codes", (List<SelectListItem>)ViewBag.ListOfCodes , new { style = "max-width: 600px;" })%>
now, before it reaches the view, the "list" has populated it with items and has marked the item which is already selected. but when it gets to the view, none of the options are marked as selected.
my question is, is it possible to use a viewbag to pass the items or should i use a different medium? as it removes the selected flag on the options if i use it that way.
Try like this:
ViewBag.ListOfCodes = new SelectList(mymodelinstance.Codes, "Id", "Name");
ViewBag.Codes = "C";
and in your view:
<%= Html.DropDownList(
"Codes",
(IEnumerable<SelectListItem>)ViewBag.ListOfCodes,
new { style = "max-width: 600px;" }
) %>
For this to work you obviously must have an item with Id = "C" inside your collection, like this:
ViewBag.ListOfCodes = new SelectList(new[]
{
new { Id = "A", Name = "Code A" },
new { Id = "B", Name = "Code B" },
new { Id = "C", Name = "Code C" },
}, "Id", "Name");
I am using the following to generate a drop down list:
#for (var index = 0; index < Model.AdminSummaries.Count(); index++)
{
<div class="rep_tr0">
<div class="rep_td0">
#Html.DropDownListFor(x => Model.AdminSummaries[index].Status,
AdminStatusReference.GetAdminStatusOptions(),
new { id = string.Format("Status_{0}",index ) })
</div>
</div>
}
Here's the HTML it generates:
<select id="Status_1" name="AdminSummaries[1].Status"><option value="1">Released</option>
<option value="2">Review</option>
<option value="3">New</option>
</select>
Here's the class that gives the status options.
public static class AdminStatusReference
{
public static IEnumerable<SelectListItem> GetAdminStatusOptions()
{
return new[]
{
new SelectListItem { Value = "1", Text = "Released" },
new SelectListItem { Value = "2", Text = "Review" },
new SelectListItem { Value = "3", Text = "New" }
};
}
}
Everything works good EXCEPT it doesn't select the items correctly. There's no option with 'selected' to match the data in the AdminSummaries.
How can I make it so the correct select list items are selected?
Just to clarify this. My problem is that if there is a data record with a value of 3 for the status then when I look at the screen I see a select list with the word "Release" showing.
What I need is for the select list to show text that corresponds with the data value.
Here is the more accurate answer
public static class AdminStatusReference
{
public static IEnumerable<SelectListItem> GetAdminStatusOptionsFor(AdminSummaries arg)
{
var options = new[]
{
new SelectListItem { Value = "1", Text = "Released" },
new SelectListItem { Value = "2", Text = "Review" },
new SelectListItem { Value = "3", Text = "New" }
};
options.First(o=> o.Value == arg).Selected = true;
return options;
}
}
Set the SelectListItem.Selected property to true:
public static class AdminStatusReference
{
public static IEnumerable<SelectListItem> GetAdminStatusOptions()
{
return new[]
{
new SelectListItem { Value = "1", Text = "Released", Selected = true },
new SelectListItem { Value = "2", Text = "Review" },
new SelectListItem { Value = "3", Text = "New" }
};
}
}
It seams from the source code that the DropDownListFor method (actually the ViewDataEvaluator.Eval method) doesn't support expressions containing indexers. Because your expression: AdminSummaries[index].Status contains an indexer that's why the framework doesn't use the selected value from your model class.
The only solution is to specify the selected item when setting the SelectListItem collection, you can do this by passing the currently selected value to your GetAdminStatusOptions method:
View:
#Html.DropDownListFor(x => Model.AdminSummaries[index].Status,
AdminStatusReference.GetAdminStatusOptions(Model.AdminSummaries[index].Status),
new { id = string.Format("Status_{0}",index ) })
A sample GetAdminStatusOptions implementation:
public static IEnumerable<SelectListItem> GetAdminStatusOptions(string selected = null)
{
var options = new[]
{
new SelectListItem {Value = "1", Text = "Released"},
new SelectListItem {Value = "2", Text = "Review"},
new SelectListItem {Value = "3", Text = "New"}
};
foreach (var option in options)
{
option.Selected = option.Value == selected;
}
return options;
}
I have to bind an Html.DropDownList with just two items statically.
Text="Yes" Value="1"
Text="No" Value="0"
The important thing is that, I have to set the text and value fields.
How can I do this?
I used this is properly working
#Html.DropDownList("Status", new List<SelectListItem>
{
new SelectListItem{ Text="Active", Value = "1" },
new SelectListItem{ Text="Not-Active", Value = "0" }
})
It is a best practice not to create the SelectList in the view. You should create it in the controller and pass it using the ViewData.
Example:
var list = new SelectList(new []
{
new { ID = "1", Name = "name1" },
new { ID = "2", Name = "name2" },
new { ID = "3", Name = "name3" },
},
"ID", "Name", 1);
ViewData["list"]=list;
return View();
you pass to the constratctor: the IEnumerable objec,the value field the text field and the selected value.
in the View:
<%=Html.DropDownList("list",ViewData["list"] as SelectList) %>
Code below assumes you are using razor view engine if not you will need to convert it.
#{
var listItems = new List<ListItem>();
listItems.Add(new ListItem{Text="Yes", Value="1"});
listItems.Add(new ListItem{Text="No", Value="0"});
}
#Html.DropDownListFor(m=>m.SelectedValue, listItem);
You should consider creating the model in your code instead of the view. Also this would be a good candidate for an editor template.
if you want to be alittle explicity then try
#{
var domainsList = new SelectList(new []
{
new SelectListItem { Text = ".Com", Value = ".com", Selected = true },
new SelectListItem { Text = ".Shopping", Value = ".shopping"},
new SelectListItem { Text = ".Org", Value = ".org"},
new SelectListItem { Text = ".Net", Value = ".net"},
new SelectListItem { Text = ".AE", Value = ".ae"},
new SelectListItem { Text = ".Info", Value = ".info"},
}, "Value", "Text");
}
#Html.DropDownList("TopLevelDomains", domainsList)
This solved it for me:
<td>
#{ var RlistItems = new List<SelectListItem>();
RlistItems.Add(new SelectListItem { Text = "Select Room Type", Value = "0" });
RlistItems.Add(new SelectListItem { Text = "Meeting Room", Value = "1" });
RlistItems.Add(new SelectListItem { Text = "Office", Value = "2" });
RlistItems.Add(new SelectListItem { Text = "Cafeteria", Value = "3" });
}
#Html.DropDownListFor(model=>model.FirstOrDefault().RoomType
,RlistItems,RlistItems[item.RoomType.Value].Selected=true )
</td>
<select asp-for="CountryName" asp-items=#(new List<SelectListItem> { new SelectListItem {Text="India",Value="1" } ,new SelectListItem {Text="Japan",Value="2" }} ) class="form-control">
<option>SELECT COUNTRY -- </option>