I end up with three values in my DropDown... Two expected values and an additional value that is the primary key of the selecteditem, ie. "2"
How do I get rid of the "2", and still select the appropriate item?
#Html.DropDownListFor(x => x.ComicBookId, ComicNet.Models.ComicBook.GetValues(), Model.ComicBookId.ToString(), new { #id = "ComicBookId" })
public partial class ComicBook
{
public static SelectList GetValues()
{
using (ApplicationDbContext db = new ApplicationDbContext())
{
SelectList selectList = new SelectList(db.ComicBooks.ToList(), "ComicBookId", "Name");
return selectList;
}
}
}
Simply remove the third parameter as it is setting the optionLabel:
#Html.DropDownListFor(x => x.ComicBookId, ComicNet.Models.ComicBook.GetValues(), new { #id = "ComicBookId" })
This is the overload that you're using: SelectExtensions.DropDownListFor Method (HtmlHelper, Expression>, IEnumerable, String, Object)
Here's the one you want: SelectExtensions.DropDownListFor Method (HtmlHelper, Expression>, IEnumerable, Object)
Related
I have a Kendo DropDownList on the View and I want to pass its DataTextField value to the Controller and then pass and them on the labels in another View. Although I can pass DataValueField values to the Controller, I cannot pass DataTextField values. I tried to apply different scenarios but I could not. Any idea? On the other hand, if it is not possible, should the DataTextField values be populated again on the Controller and return to the other View?
View:
#model IssueViewModel
...
#Html.LabelFor(m => m.ProjectID)
#(Html.Kendo().DropDownList()
.Name("ProjectID")
.DataTextField("ProjectName")
.DataValueField("ProjectId")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetProjects", "Issue");
});
})
)
Controller:
public JsonResult GetProjects()
{
var projects = repository.Projects;
return Json(projects.Select(m => new { ProjectId = m.ID, ProjectName = m.Description }), JsonRequestBehavior.AllowGet);
}
/* I want to pass the DataTextField values to this
method and return them to the CreateManagement view */
public ActionResult Create(IssueViewModel issueViewModel)
{
return RedirectToAction("CreateManagement", issueViewModel);
}
Change your controller to this:
public JsonResult GetProjects()
{
var projects = repository.Projects;
return Json(projects.Select(m => new SelectListItem { ProjectId = m.Description, ProjectName = m.Description }).ToList(), JsonRequestBehavior.AllowGet);
}
Since the DropDownList uses DataTextField for the user and uses DataValueField for the server communications, so you have to use DataTextField value for both. Then you can use it for the next operations.
Edit: if you need both values on the controller, change JsonResult method to :
return Json(projects.Select(m => new SelectListItem { ProjectId = m.Description + "," + m.ID , ProjectName = m.Description }).ToList(), JsonRequestBehavior.AllowGet);
Now you can use both in the next operations just by spiting them like:
var _both = value.split(',');//value: returned value from the view
I'm trying to create a select list. I've created it just fine using a collection from my viewmodel that allows me to set each option's value and text with the following code:
#Html.DropDownListFor(model => model.Networks, new SelectList(Model.Networks, "NetworkID", "Name"), new { #class="form-control" })
Model.Networks contains another property called CountryId. I'd like to add an attribute to each option tag so it looks like:
<option value="[NetworkId]" data-countryId="[CountryId]">Canada</option>
Which way should I go about doing this?
You can create a Form Helper class to create a custom drop down list, and create a custom 'selectListItem' class that has an extra property 'itemsHtmlAttributes' of type IDictionary - see below. You may need to play around with the 'id' or 'name' attributes to get the default model binding working. Below is a bit messy, I would suggest using TagBuilder to build the 'select' and 'option' tags:
public class SelectListItemCustom : SelectListItem
{
public IDictionary<string, object> itemsHtmlAttributes { get; set; }
}
public static class FormHelper
{
public static MvcHtmlString DropDownListForCustom(this HtmlHelper htmlHelper, string id, List<SelectListItemCustom> selectListItems)
{
var selectListHtml = "";
foreach (var item in selectListItems)
{
var attributes = new List<string>();
foreach (KeyValuePair<string, string> dictItem in item.itemsHtmlAttributes)
{
attributes.Add(string.Format("{0}='{1}'", dictItem.Key, dictItem.Value));
}
// do this or some better way of tag building
selectListHtml += string.Format(
"<option value='{0}' {1} {2}>{3}</option>", item.Value,item.Selected ? "selected" : string.Empty,string.Join(" ", attributes.ToArray()),item.Text);
}
// do this or some better way of tag building
var html = string.Format("<select id='{0}' name='{0}'>{1}</select>", id, selectListHtml);
return new MvcHtmlString(html);
}
}
VIEW:
#{
var item = new SelectListItemCustom { Selected = true, Value = "123", Text = "Australia", itemsHtmlAttributes = new Dictionary<string, object> { { "countrycode", "au" } } };
var items = new List<SelectListItemCustom> { item };
Html.Raw(Html.DropDownListForCustom("insertIdHere", items))
}
I am working on a MVC project.I have a view having a dropdownlist with an option label "Select Task".Now the integer property bound with this dropdown is not a required field.
But then too after I try to save, I get the dropdown having a red border showing that it is required. When I analysed, I found that the option label has value null.
Using firebug when I entered 0 for the value of option label, the view was saved with no model state error. Am I doing something wrong ? How to avoid it ?
View
#Html.DropDownListFor(model => model.projecttaskid, new SelectList((IList<SelectListItem>)ViewData["MyTasks"], "Value", "Text"),"Select Task", new { #class = "span2" })
Model public int projecttaskid { get; set; } Controller It doesn't reach the controller action.
projecttaskid is not nullable. Unless you provide a default value for the drop down list, the model will not bind properly, which is why you are getting validation error even though the model field is not marked as [required].
Edit: by default value I mean an item in the list with a value of 0, since the default value for projecttaskid is 0.
For instant, you use an overload of DropDownListFor with the optionLabel argument (your "Select Task" argument.
If no item is selected, this will be taken as the "selected option", and return a null value for model.projecttaskid.
The easiest way would be to add an element with a 0 value when you create your list (ViewData["MyTasks"])
With, for example :
Value = 0;
Text = "Select Task;
And use an overload of DropDownListFor without the optionLabel.
[By the way, usage of ViewModels instead of ViewData would be a good thing, but that's another problem]
*EDIT *
We do use some extension methods to manage these cases :
public static IEnumerable<SelectListItem> ToSelectListItem<T, TValue, TText>(
this IEnumerable<T> enumerable,
Func<T, TText> text,
Func<T, TValue> value)
{
return enumerable.Select(item => new SelectListItem
{
Text = text(item).ToString(),
Value = value(item).ToString()
}).AsEnumerable();
}
public static IEnumerable<SelectListItem> WithDefaultZeroValue(this IEnumerable<SelectListItem> selectListItems, string chooseText/* = ChooseText*/)
{
IList<SelectListItem> items = selectListItems.ToList();
items.Insert(0, new SelectListItem { Value = "0", Text = chooseText });
return items.AsEnumerable();
}
usage
var myList = mySourceForDropDown.ToSelectListItem(m => m.TextField, m => m.ValueField)
.WithDefaultZeroValue("SelectTask")
use this:
#Html.DropDownListFor(model => model.Type, new SelectList(Enum.GetNames(typeof(Enums.TenderType))), new Dictionary<string, object>() { { "data-val", "false" } })
I am binding an MVC (3) selectList to an enum using the following helper method
public static List<SelectListItem> GetSelectList<T>()
{
Type enumType = typeof(T);
if (!enumType.IsEnum)
throw new ArgumentException("The specified type is not enum");
List<SelectListItem> enumList = new List<SelectListItem>();
var values = Enum.GetValues(enumType);
foreach (var value in values)
{
SelectListItem newItem = new SelectListItem();
newItem.Value = Convert.ToInt32(value).ToString();
newItem.Text = Regex.Replace(Enum.GetName(enumType, value), "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ");
enumList.Add(newItem);
}
return enumList;
}
Then calling the method in my controller and passing the fourth parameter to the selectList constructor as the preselected id of the customer type.
_view.CustomerTypeSelectList = new SelectList(EnumHelper.GetSelectList<CustomerTypeEnum>(), "Value", "Text", _customer.TypeID);
Then in the view I bind the selectList
<%=Html.DropDownListFor(x => x.CustomerTypeId, Model.CustomerTypeSelectList )%>
However I cannot get the selectList to pre-populate.
Any ideas?
You fill the enumList with string-string value pairs so when specifying the selected element you should use string as well (with Convert.ToInt32 and ToString).
In your GetSelectList helper you should return SelectList like this:
_view.CustomerTypeSelectList = new SelectList(EnumHelper.GetSelectList<CustomerTypeEnum>(), "Value", "Text", Convert.ToInt32(_customer.TypeID).ToString());
Better solution would be to use enum values for value column and return SelectList object from GetSelectList:
public static SelectList GetSelectList<T>()
{
Type enumType = typeof(T);
if (!enumType.IsEnum)
throw new ArgumentException("The specified type is not enum");
var values = Enum.GetValues(enumType);
var enumList = values.Select(e=>new { Value = e , Text = Regex.Replace(Enum.GetName(enumType, e), "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ") })
var selectList = new SelectList(values, "Value", "Text", enumObj);
return selectList;
}
This has totally puzzled me.
Here's my View:
#Html.DropDownListFor(model => model.ScoreDescription,
Model.RatingOptions,
"--",
new { #id = clientId })
And the model:
public decimal? Score { get; set; }
public SelectList RatingOptions
{
get
{
var options = new List<SelectListItem>();
for (var i = 1; i <= 5; i++)
{
options.Add(new SelectListItem
{
Selected = Score.HasValue && Score.Value == Convert.ToDecimal(i),
Text = ((decimal)i).ToRatingDescription(ScoreFactorType),
Value = i.ToString()
});
}
var selectList = new SelectList(options, "Value", "Text");
// At this point, "options" has an item with "Selected" to true.
// Also, the underlying "MultiSelectList" also has it.
// Yet selectList.SelectedValue is null. WTF?
return selectList;
}
}
As the comments suggest, i can't get the selected value to happen.
Is it something to do with the fact i'm using a nullable decimal ? After that loop, options is correct in that it has exactly 1 item with select to true, so it seems i'm doing the right thing.
Now, if i use a different SelectList overload:
var selectedValue = Score.HasValue ? Score.Value.ToString("0") : string.Empty;
var selectList = new SelectList(options, "Value", "Text", selectedValue);
It works. Why? At first i thought it might be a LINQ-trick (e.g deferred execution), but i tried forcing a .ToList() and there is no difference.
It's like setting the Selected property as you create the SelectListItem has no effect, and you have you set it at the end using the SelectList ctor parameter.
Can anyone shed some light on this?
If you look at the implementation of the SelectList class it never actually uses the fact that you are passing a SelectListItem. It works with an IEnumerable. So the Selected property of a SelectListItem is not used. Personally I prefer setting the selected value of a dropdown by setting the value of the corresponding property that you are binding the ddl to.
Example:
public int? Score { get; set; }
public SelectList RatingOptions
{
get
{
var options = Enumerable.Range(1, 5).Select(i => new SelectListItem
{
Text = ((decimal)i).ToRatingDescription(ScoreFactorType),
Value = ((decimal)i).ToString()
});
return new SelectList(options, "Value", "Text");
}
}
and then in the controller action simply set the Score property to the necessary value and in the view use this Score property to bind to:
#Html.DropDownListFor(
model => model.Score,
Model.RatingOptions,
"--",
new { #id = clientId }
)