I have a model:
public class DocumentModel
{
public int TypeID { get; set; }
public List<SelectListItem> DocumentTypes { get; set; }
}
I have a view:
#Html.DropDownListFor(x => x.TypeID, Model.DocumentTypes, "- please select -")
I populate my drop down
var model = new DocumentModel();
model.DocumentTypes = GetDocumentTypes();
private static List<SelectListItem> GetDocumentTypes()
{
var items = new List<SelectListItem>
{
new SelectListItem
{Text = #"Text #1", Value = "1"},
new SelectListItem
{Text = #"Text #2", Value = "2"},
};
return items;
}
I have a controller action when the form is posted back:
[HttpPost]
public void UploadDocument(DocumentModel model)
{
if (ModelState.IsValid)
{
// I want to get the text from the dropdown
}
}
How do i get the text from my drop down list? Thanks
You may not get this easily with the default model binding. You have to a small workaround like this.
1) Add a new property to your model/viewmodel to store the selected text
public class DocumentModel
{
public int TypeID { get; set; }
public List<SelectListItem> DocumentTypes { get; set; }
public string SelctedType { set;get;}
}
2) Use Html.HiddenFor Helper method to create a hidden variable in the form for this property
#Html.HiddenFor(x => x.SelctedType)
3) Use little javascript to override the submit ! ie; When user submits the form, Get the selected Text from the dropdown and set that value as the value of the Hidden field.
$(function () {
$("form").submit(function(){
var selTypeText= $("#TypeID option:selected").text();
$("#SelctedType").val(selTypeText);
});
});
Now in your HTTPPost action method, This will be available in the SelectedType property.
[HttpPost]
public void UploadDocument(DocumentModel model)
{
if(ModelState.IsValid)
{
string thatValue=model.SelectedType;
}
}
if what you want to do is to retrieve selected item then this can do the work :
var selecteItem = model.DocumentTypes.Where(item=>item.Selected).FirstOrDefault();
Cheers!
On your model I would have another string -
public string Selected{ get; set; }
then in your view :
#Html.DropDownListFor(model => model.Selected, new SelectList(Model.DocumentTypes, "Value", "Text"))
I stumbled here trying to find the way to get the text value out of a SelectList to display it in a format other than a DropDownList (I'm reusing my Edit ViewModel as it has all the data I required)
var text = selectList.Where(q => q.Selected == true).First().Text;
Related
I'm trying to use SelectListItem for an MVC project, drop down is populated as I expect it. But when I pass the selected value to a function that accepts string using this model.CodeDropDown.ToString() I get System.Collections.Generic.List 1[System.Web.Mvc.SelectListItem] which is not a string.
How can I get the selected value as string?
I have a ViewModel class that looks like this:
public class HomeViewModel
{
[Required]
[DisplayName("Code")]
public IEnumerable<SelectListItem> CodeDropDown { get; set; }
public string SelectedValue { get; set; }
}
I'm filling up the dropdown using this Controller
public ActionResult Index()
{
var model = new HomeViewModel();
using (var dbCon = new SomeDBContext())
{
model.CodeDropDown = dbCon.CodeID.ToList().Select(x => new SelectListItem
{
Value = x.Name.ToString(), Text = x.CodeDropDown.ToString()
}).DistinctBy(c => c.Value);
}
return View(model);
}
}
I'm trying to use the value from SelectListItem like this,
public ActionResult Index(HomeViewModel model)
{
var results = mainDbContext.GetSomeResult(model.CodeDropDown.ToString(), model.Prop2, model.Prop3);
return View(results);
}
View looks like this:
#Html.DropDownListFor(model => model.SelectedValue, Model.CodeDropDown, "--")
Add one more property (SelectedThingId or something more meaningful) to your HomeViewModel to hold the value of the selected thing from the dropdown.
In your view (you have not posted code for view) have something like this:
#Html.DropDownListFor(x=>x.SelectedThingId, Model.CodeDropDown)
Then in your controller you can get this value using:
model.SelectedThingId; // model is passed into your controller has you have it.
Add 2 properties in the model
public string CodedropdownID{ get; set; } //to store the selected dropdown value Id
public string CodedropdownText{ get; set; } //to store the selected dropdown value text
Change the View as following and add onchange event to dropdown:
#Html.DropDownListFor(m=> m.CodedropdownID, m.CodeDropDown, "--")
#Html.Hiddenfor(m=>m.CodedropdownText)
Add the following script:
<script type="text/javascript">
$("#CodedropdownID").on("change", function {
$("#CodedropdownText").val($(this).text());
});
</script>
Change the controller method
public ActionResult Index(HomeViewModel model)
{
var results = mainDbContext.GetSomeResult(model.CodedropdownText.ToString(), model.Prop2, model.Prop3);
return View(results);
}
I've been following some guidance for a listbox and trying to handle the selections properly. What is stumping me and I can't seem to find relevant material on is accessing the value(s) selected. There may be only one selected but most likely there will be multiple selected at a time.
my post controller is getting the object model and it has the value of one of the selected items but not all of them? Do I need to run some jquery before the post as other articles have said? Doesn't seem right but maybe...
My model:
public partial class ExtrnlSubsModel : BaseEntityModel
{
public IList<SelectListItem> AvailableForums { get; set; }
public int ExtForumId { get; set; }
}
My razor:
#Html.ListBoxFor(model => model.ExtForumId, Model.AvailableForums, new { style = "width:500px;height:250px" })
#Html.RequiredHint()
#Html.ValidationMessageFor(model => model.ExtForumId)
My controller:
[HttpPost]
public ActionResult ExtForumAdd(ExtrnlSubsModel model)
{ .... }
So as I mentioned my model gets populated but only with a single selection despite having ctrl-clicked numerous items.
TIA
Change your model to use a MultiSelect and an array of ints for the selected items like this (partial removed for simplicity):
public class ExtrnlSubsModel
{
public MultiSelectList AvailableForums { get; set; }
public int[] ExtForumIds { get; set; }
}
Change your list box to this, with your array of ints property first:
#Html.ListBoxFor(model => model.ExtForumIds, Model.AvailableForums, new { style = "width:500px;height:250px" })
For test purposes a controller get action:
public ActionResult Index()
{
var items = new List<SelectItem>();
// These items would be set from your db
var items = new List<SelectItem>();
items.Add(new SelectItem { Id = 1, Name = "1" });
items.Add(new SelectItem { Id = 2, Name = "2" });
var selectedItems = new List<SelectItem>();
selectedItems.Add(new SelectItem { Id = 1, Name = "1" });
var model = new ExtrnlSubsModel();
// project the selected indexs to an array of ints
int[] selectedItemsArray = selectedItems.Select(s => s.Id).ToArray();
model.ExtForumIds = selectedItemsArray;
model.AvailableForums = new MultiSelectList(items, "ID", "Name", selectedItemsArray);
return View(model);
}
Post action:
[HttpPost]
public ActionResult Index(ExtrnlSubsModel model)
{
var selectedItems = model.ExtForumIds;
return View(model);
}
I have also used a test SelectItem for demo, this would be the object that you are returning instead:
public class SelectItem
{
public int Id { get; set; }
public string Name { get; set; }
}
Picture of the selected items posted back below:
I have a custom view model like this:
namespace MyCustomNamespace.Models
{
public class CustomViewModel
{
public CustomViewModel()
{
FirstViewModel = new FirstModel ();
SecondViewModel = new SecondModel ();
}
public FirstModel FirstViewModel { get; set; }
public SecondModel SecondViewModel { get; set; }
}
}
namespace MyCustomNamespace.Models
{
public class FirstModel
{
public string id { get; set; }
public string text { get; set; }
public IEnumerable<SelectListItem> Items
{
(...)
}
(...)
}
}
SecondModel is similar to FirstModel.
in my view i do using razor:
#model MyCustomNamespace.Models.CustomViewModel
(...)
#Html.DropDownListFor(m => m.FirstViewModel.Id, Model.FirstViewModel.Items)
(...)
I populate the dropdownlist with a model.
I am trying to know which is the current selected element in the dropdownlist shown above, but i do not know how.... maybe through the model? but how?
Updated:
This is my real model type, above was an example about what i was doing. FirstModel would be ComponentTypeModel in this case:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System;
using Resources;
namespace MyCustomNamespace.Models
{
public class ComponentTypeModel
{
private readonly List<ComponentType> componentTypes;
public ComponentTypeModel()
{
using (ConfigContext dbContext = new ConfigContext())
{
try
{
componentTypes = dbContext.ComponentTypes.ToList();
}
catch (Exception ex)
{
//EventLogger.LogException(ex);
}
}
}
[Display(Name = "Component Type")]
public int SelectedCompTypeId { get; set; }
public IEnumerable<SelectListItem> CompTypeItems
{
get
{
var allCompTypes = componentTypes.Select(f => new SelectListItem
{
Value = f.ComponentTypeId.ToString(),
Text = f.Name
});
return DefaultCompTypeItem.Concat(allCompTypes);
}
}
public IEnumerable<SelectListItem> DefaultCompTypeItem
{
get
{
return Enumerable.Repeat(new SelectListItem
{
Value = "-1",
Text = "Select a component type"
},
count: 1);
}
}
}
}
In your models, you are using
public IEnumerable<SelectListItem> Items
{
(...)
}
That is fine, but doing so, you need to set manually the selected item. I suggest you to use a SelectList instead of a list of SelectListItems.
So, in your ViewModel, you need:
public SelectList Items {get; set;}
In your controller you populate that SelectList:
var myItems = GetMyCollectionOfItems(); //The list to display in the DropDownList
model.FirstViewModel.Items = new SelectList(myItems, "NameOfValueField", "NameOfTextField", selectedValue); //The selected value is optional
Then in your View you use:
#Html.DropDownListFor(m => m.FirstViewModel.Id, Model.FirstViewModel.Items, "--- Select Item---", new { #id = "firstModelID" })
Check that is the same code you used, but this way, is the SelectList who knows which item is selected and you don't need to do nothing manually. Just load the id of the select items in the SelectList constructor.
Then, if you need to know in client side which is the selected item, in order to use it in Javascript to hide something or something like that, you can do what the other people answers:
$( document ).ready(function() {
var mySelectedValue = $('#firstModelID').val();
alert(mySelectedValue);
});
If you need to know when the select value changes:
$( document ).ready(function() {
$('#firstModelID').change(function() {
alert($('#firstModelID').val());
});
});
AFTER YOUR UPDATE:
All the code you have in the Model, can be greatly simplified using the code in this answer.
You should do a little change: Make the
[Display(Name = "Component Type")]
public int SelectedCompTypeId { get; set; }
[Display(Name = "Component Type")]
public int? SelectedCompTypeId { get; set; } //Now this is nullable
If you do this way, you don't need to add the default item thing... just use:
#Html.DropDownListFor(m => m.FirstViewModel.Id, Model.FirstViewModel.Items, "Select a component type", new { #id = "firstModelID" })
Then in your controller, you can see it is Null you do the equivalent a what you do when you received the "-1".
Now, all the database access should be away of the model. The model is much cleaner this way:
public class ComponentTypeModel
{
[Display(Name = "Component Type")]
public int? SelectedCompTypeId { get; set; }
public SelectLis CompTypeItems { get; set:}
}
Then in your controller you do:
var model = new ComponentTypeModel();
model.CompTypeItems = new SelectList(dbContext.ComponentTypes.Select(x => x.Name, x.ComponentTypeId), "ComponentTypeId", "Name");
If you want to have one of them selected by default (as you usually do in an Edit view), you do this:
var model = new ComponentTypeModel();
model.CompTypeItems = new SelectList(dbContext.ComponentTypes.Select(x => x.Name, x.ComponentTypeId), "ComponentTypeId", "Name", myDefaultValue); //where the myDefaultValue is an int
The razor code in your view should remain the same, since all the information about selected item, collection of items, fields to be mapped remains in the controller and model.
If you trying to know it before submitting the form (on client side)
#Html.DropDownListFor(m => m.FirstViewModel.Id, Model.FirstViewModel.Items, "--- Select Item---", new { #id = "firstModelID" })
and you could check its value by: $('#firstModelID').val();
There's no way to identify that in C# on the client side, you'd have to use jQuery/JavaScript for that, something like:
$("#FirstViewModel_Id").val();
var Id = $("#FirstViewModel_Id").val();
alert(Id);
In addition to the answers here, you can also do like this:
$("#FirstViewModel_Id option:selected").val();
The selected value will be in the Id property of the posted model (FirstViewModel) after a post to the server.
You can access the
If you want to get the selected value on the client you can use:
$("#FirstViewModel_Id").val();
or
$("#FirstViewModel_Id option:selected").val();
if the first one doesn't work.
In my application, I have two dropdownlists. First to display country values and second to display the states of selected countries. The values are generated and displayed in both dropdownlists. But on post, both dropdownlist return the id of the model values and not the name or value. How to bind the selected item text of dropdownlist on post ?
Model :
public string State { get; set; }
public string Country { get; set; }
public SelectList CountryList { get; set; }
public SelectList RegionList { get; set; }
public class Countries
{
public string ID { get; set; }
public string Name { get; set; }
}
public class Region
{
public string ID { get; set; }
public string Name { get; set; }
}
View
#Html.DropDownListFor(model =>model.State, new SelectList(Model.RegionList, "Value", "Text", Model.RegionList.SelectedValue))
#Html.DropDownListFor(model => model.Country, new SelectList(Model.CountryList, "Value", "Text", Model.CountryList.SelectedValue), new { data_url = Url.Action("GetRegionDetail", "WPindex") })
<script type="text/javascript">
$(document).ready(function () {
$("#Country").change(function () {
$("#State").empty();
var url =$(this).data(url);
var Id = $('#Country option:selected').attr('value');
$.getJSON(url, { ID: Id },
function (data) {
jQuery.each(data, function (key, Region) {
$("#State").append($("<option></option>").val(Region.ID).html(Region.Name));
}
);
});
});
});
</script>
Controller :
public JsonResult GetRegionDetail(int ID)
{
AddressModel amodel = new AddressModel();
List<Model.Region> objRegion = new List<Model.Region>();
objRegion = GetRegionList(ID);
SelectList objlistofRegiontobind = new SelectList(objRegion, "ID", "Name", 0);
amodel.RegionList = objlistofRegiontobind;
return Json(objRegion, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public ActionResult UpdateDetails(Model objmodel)
{
string state = objmodel.State; // returns ID and not Name (selected text)
string country = objmodel.Country; // returns ID and not Name
}
When you define a dropdown list in Html, each option has an attribute for value and text the text value is shown to the user and the value is the "selected value" of that dropdown. When the form is posted to the controller, only the value is posted. If you wish to have the name instead of the Id to post, simply set the value attribute of the dropdown list items to the name of the source data.
For example, when you populate your state dropdown you could do it like this:
$("#State").append($("<option></option>").val(Region.Name).html(Region.Name));
That's not a problem. You want the DropDownList to give you the selected Value which in this case is the ID, not the Text. So, I would recommend that you change the properties of your ViewModel with the following:
public int StateID { get; set; }
public int CountryID { get; set; }
public SelectList CountryList { get; set; }
public SelectList RegionList { get; set; }
However, if you don't want the IDs, you can define your DropDownLists like this:
#Html.DropDownListFor(model => model.State, new SelectList(Model.RegionList, Model.State))
#Html.DropDownListFor(model => model.Country, new SelectList(Model.CountryList, Model.Country), new { data_url = Url.Action("GetRegionDetail", "WPindex") })
I'm trying to teach myself MVC3. Im converting from webforms.
I need to create a view model that includes a dropdown list that I can pass to the controller and eventually render in the View.
How can I accomplish this? I have the skeleton but I dont know what the code is to actually create the name value pairs for the view.
namespace DH.ViewModels
{
public class SharedLayoutViewModel
{
public IEnumerable<SelectListItem> Products
{
//some code to setup the value/name pairs to be rendered in the view.
//example:
//<option value="1">Mustard</option>
//<option value="2">Ketchup</option>
//<option value="3">Mayo</option>
//<option value="4">Relish</option>
//<option value="5">BBQ</option>
}
}
}
Thanks
I would create a class for Product and the create Products Property in my main viewmodel which is of type List
public class ProductViewModel
{
public int ID { set;get;}
public string Name { set;get;}
}
public class OrderViewModel
{
public int OrderNumber { set;get;}
public List<ProductViewModel> Products { set;get;}
public int SelectedProductId { set;get;}
}
and in your Controller Action method
public ActionResult Order()
{
var orderVM=new OrderViewModel();
//Items hard coded for demo. You may replace with values from your db
orderVM.Products= new List<ProductViewModel>
{
new ProductViewModel{ ID=1, Name="IPhone" },
new ProductViewModel{ ID=2, Name="MacBook Pro" },
new ProductViewModel{ ID=3, Name="iPod" }
};
return View(orderVM);
}
and in your view which is strongly typed to OrderViewModel.
#model ORderViewModel
#using (Html.BeginForm())
{
<p>
#Html.DropDownListFor(x => x.SelectedProductId ,
new SelectList(Model.Products, "ID", "Name"), "-- Select Product--")
</p>
<input type="submit" />
}
I have added a SelectedProductId property also, so you will get the user selected value from the dropdown in that Property when user post the form back to the controller.
You can also use the generic SelectListItem type collection as your view model property to transfer the dropdown data instead of your custom ProductViewModel collection.
public class OrderViewModel
{
public int OrderNumber { set;get;}
public List<SelectListItem> Products { set;get;}
public int SelectedProductId { set;get;}
}
and in the GET action,
public ActionResult Order()
{
var orderVM=new OrderViewModel();
//Items hard coded for demo. You may replace with values from your db
orderVM.Products= new List<SelectListItem>
{
new SelectListItem {Value = "1", Text = "IPhone"},
new SelectListItem {Value = "2", Text = "MacBook"},
new SelectListItem {Value = "3", Text = "Candy"}
};
return View(orderVM);
}
And in your view,
#Html.DropDownListFor(x => x.SelectedProductId, Model.Products, "-- Select Product--")
EDIT : As per the request from OP, edited the answer to have the Property returning static items as products
I added a get implementation to Products property to return a list of static products.
public class OrderViewModel
{
private List<ProductViewModel> _products;
public int OrderNumber { set; get; }
public List<ProductViewModel> Products
{
get
{
if (_products == null)
{
_products = new List<ProductViewModel>();
_products.Add(new ProductViewModel { ID = 1, Name = "Ketchup" });
_products.Add(new ProductViewModel { ID = 1, Name = "Mustard" });
_products.Add(new ProductViewModel { ID = 1, Name = "Relish" });
_products.Add(new ProductViewModel { ID = 1, Name = "Mayo" });
}
return _products;
}
}
public int SelectedProductId { set;get;}
}
Now in your controller, you don't need to call the GetAvailableProductsmethod as it is already there. So the controller will looks like this.
public ActionResult Order()
{
OrderViewModel orderVM = new OrderViewModel();
return View(orderVM);
}
Here is the output.
If you have many items in the products, move it to a method and call that method int he get implementation instead of writing that there. That is much cleaner approach.
I prefer to do it this way.
#Html.DropDownListFor(m => m.ProductId, new SelectList(Model.Products, "ID", "Name"))
So my view model just contains a list of products and generate the select list on the view.
Why can't you just use SelectList within your ViewModel?
It's kind of abstraction that contains selected value and list of items itself.
You can implement Display / Editor templates and define attribute DataTypeAttribute/UIHintAttribute associate specific template with Select List.
public class ProductViewModel
{
public int ID { set;get;}
public string Name { set;get;}
public SelectList Items {get;set;}
}