How to fetch selected value from a dropdownlist in MVC3 - asp.net-mvc

This may sound simple but i am stuck up at a very strange problem.
I have created dropdown's in my application and i am not able to fetch the selected value On Edit.
Here is my View:
<div class="editor-field">
#Html.DropDownListFor(model => model.Hobbyhome.HobbyHomeAddressList.First().ProvincialState.ProvincialStateID, new SelectList(ViewBag.State, "ProvincialStateID", "ProvincialStateName"), "-----Select State-----", new { #id = "State" })<font color="red">*</font>
</div>
i have written a function in controller to fetch the value and i am also able to fetch the value but when it goes in View it doesnot show me the value
i have created another dropdown like this:
#Html.DropDownListFor(model => model.Hobbydetail.Hobbymaster.HobbyId, new SelectList(ViewBag.Hobby, "HobbyId", "HobbyName"), "----Select Hobby----", new { #id = "Hobby" })<font color="red">*</font>
And the strange thing is i can see the value of the second dropdown but not for first One
What i think is maybe because i am using an list.First() in the first dropdown and so it isgiving this problem bcoz On edit view page it only shows me "-----Select State--" as value for first dropdown.
Please Help me

To get the "selected value object" in you edit view :
#Html.DropDownListFor(model => model.Hobbydetail.Hobbymaster.HobbyId,
new SelectList(ViewBag.Hobby, "HobbyId", "HobbyName", Model.Hobbydetail.Hobbymaster.HobbyId),
"----Select Hobby----", new { #id = "Hobby" })
To have all elements in your DropDown, be sure that your ViewBag.Hobby is initialized and filled in your controller before showing Edit view!

First() method returns the first element of a sequence. It will throw you an exception if the source sequence is empty.
Why you need to use First() there ? I think you are doing it in the wrong way. your first paramenter of DropDownListFor should be a variable which holds the selected value, in this purticular overload you are using.
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name,
IEnumerable<SelectListItem> selectList,
IDictionary<string, Object> htmlAttributes
)
name : The name of the form field to return.
You should be using the second approach
I would make a clean ViewModel to handle this. This makes my Views Clean.
public class AddHobbyViewModel
{
public int SelectedHobbyId { set;get;}
public IEnumerable<Hobby> Hobbys { set;get;}
//other relevant properties for the View.
}
In the GET action method, Instead of returning the data in ViewBag, I would return it in the ViewModel.
public ActionResult Add()
{
AddHobbyViewModel model=new AddHobbyViewModel ();
model.Hobbys=db.Hobbies(); // get all available hobbies.
return View(model);
}
And in the View,
#Html.DropDownListFor(model => SelectedHobbyId , new SelectList(Hobbys , "HobbyId", "HobbyName"), "----Select Hobby----", new { #id = "Hobby" })
Now you will have the selected value available in your httppost mehod in the SelectedHobbyId property
[HttpPost]
public ActionResult Add(AddHobbyViewModel model)
{
// check model.SelectedHobbyId here
}

Related

how to bind selectlistitem value in dropdownlist to string property in model

This is how I populate dropdownlist and create html element;
AccountController:
public ActionResult Index()
{
ViewBag.Towns = new SelectList(_skrsService.GetTowns(), "Value", "Text", 1);
return View();
}
...
public List<SelectListItem> GetTowns()
{
var list = UnitOfWork.Repository<SkrsIl>().OrderBy(x => x.Adi).Select(x => new SelectListItem()
{
Text = x.Adi,
Value = x.Kodu.ToString()
}).ToList();
return list;
}
Login.cshtml(Hometown is string field in model bindned to login view page):
#Html.DropDownListFor( x => x.Hometown, ((SelectList)ViewBag.Towns), new { #class = "form-control", placeholder = "Doğum Yeri" })
I expected this to work but getting error, message:
"The ViewData item that has the key 'Hometown' is of type
'System.String' but must be of type 'IEnumerable<SelectListItem>'."
how can I make it work properly? I just expected selectem item value to 'Hometown' property
The error means that that ViewBag.Towns is null. When the 2nd parameter (IEnumerable<SelectListItem> selectList) is null, the method expects the first parameter to be typeof IEnumerable<SelectListItem>.
Since you have assigned it in the GET method, this is almost certainly happening when you submit your form and have returned the view but have not repopulated the value of ViewBag.Towns as you did in the GET method.
As a side note, using new SelectList() is pointless extra overhead - it just creates another IEnumerable<SelectListItem> based on the first one. In addition, the 4th parameter of the SelectList constructor is ignored when you bind to a model property - internally the method builds a new IEnumerable<SelectListItem> and sets the Selected property based on the value of the property your binding to.
Your controller code should be
public ActionResult Index()
{
ViewBag.Towns = _skrsService.GetTowns();
return View(); // ideally you should be returning a model
}
[HttpPost]
public ActionResult Index(YourModel model)
{
if (!ModelState.IsValid)
{
ViewBag.Towns = _skrsService.GetTowns(); // re-populate the SelectList
return View(model);
}
// save and redirect
}
But preferably you should be using a view model containing a property for the select list rather than ViewBag.

ASP.NET MVC - Dropdown - There is no ViewData item of type 'IEnumerable<SelectListItem>'

MenuType definiation:
public string Code { get; set; }
public string Name { get; set; }
ASP.NET MVC 5
I have searched and read before I'm posting my question here,
I'm trying to LOAD the data in the asp.net mvc dropdownlist why is that so complicated?
//controller
public class ClientController : BaseController
{
public ActionResult Index()
{
List<MenuType> ctypelist = db.ContractTypes.OrderBy(x => x.TypeOfContract).ToList();
IEnumerable<SelectListItem> list = new SelectList(ctypelist.ToList());
ViewBag.DropDownTypeOfContract = list;
return View();
}
}
//html
#model myapp.Models.Client
#Html.DropDownList("Codes", (List<SelectListItem>)ViewBag.DropDownTypeOfContract , new { style = "max-width: 600px;" })%>
What's complicated is that you can't seem to decide which type you're using...
First you have a List<MenuType> (I assume ContractTypes is actually of type MenuType?) Then you create a SelectList, passing the List<MenuType> to it, which implies that MenuType must have at least two properties, one called Text and one called Value. If not, you will have to specify the Text and Value property names in the SelectList constructor parameters.
After that, for some reason you convert it to a IEnumerable<SelectListItem>, then you assign that to a ViewBag item and call your View. So, at this point, your ViewBag.DropDownTypeOfContract is of type IEnumerable<SelectListItem>.
Next, in your View, you for some reason define an #model depite not passing any model at all to the view. Ok.... Whatever...
So now we get to the real problem.
#Html.DropDownList("Codes",
(List<SelectListItem>)ViewBag.DropDownTypeOfContract ,
new { style = "max-width: 600px;" })%>
Ok, let's ignore for a moment the fact that you have a WebForms closing code block indicator (%>) for some reason... The biggest problem here is that you're trying to cast ViewBag.DropDownTypeOfContract to a List<SelectListItem>, which is something it is not, and never was.
You converted the List<MenuType> to a SelectList which you then converted to an IEnumerable<SelectListItem>. There was never any List<SelectListItem> involved.
So, the simple fix (besides rewriting your code to be sane) is to change your cast as such:
#Html.DropDownList("Codes",
(IEnumerable<SelectListItem>)ViewBag.DropDownTypeOfContract,
new { style = "max-width: 600px;" })
EDIT:
Since your MenuType does not contain the appropriate properties, you will have to modify your SelectList as such (Which I mention above). FYI, ctypelist is already a list, no need to convert it to a list again... that's just silly.
IEnumerable<SelectListItem> list = new SelectList(ctypelist, "Code", "Name");
Note: I have posted this answer without knowledge of what variables your MenuType Class has. Please add to your question and I will edit this answer according to youe MenuType Class
All Dropdowns are a collection of Value and Text Pairs.
<select>
<option value=1>TEXT 1</option>
<option value=2>TEXT 2</option>
<option value=3>TEXT 3</option>
</select>
You have a list of List<MenuType>, Which values from the MenuType do you want to display in the DropDown List?
Assuming you have this as MenuType.cs
public class MenuType
{
public int MenuTypeId {get;set;}
public string Name {get;set;}
}
Your dropDown should be generated like this:
public ActionResult Index()
{
Dictionary<int,string> ctypelist = db.ContractTypes.OrderBy(x => x.TypeOfContract).ToDictionary(s => s.MenuTypeId, s=> s.Name);
IEnumerable<SelectListItem> selectListItems = ctypelist.Select(s => new SelectListItem() { Value = s.Key.ToString(), Text = s.Value });
ViewBag.DropDownTypeOfContract = selectListItems;
return View();
}
In View:
#{
var items = (IEnumerable<SelectListItem>) ViewBag.DropDownTypeOfContract;
}
#Html.DropDownList("Codes", items , "Select Item")

Execute Controller Method from razor html view in MVC?

Ok so I have an Html.DropDownList and I want to be able to execute a controller method ActionResult output(string test) and send a parameter to it. I have something like this already but I get an Uncaught TypeError: Cannot set property 'action' of null message:
#Html.DropDownList(
"revisions", ViewData["revisions"] as SelectList,
new
{
onchange = "this.form.action = '/Shops/output('test')'; this.form.submit();"
})
How do I go about fixing my code?
If your Action method's parameter name is id,
public ActionResult output(string id)
{
//do something
}
then you may use your form action url like this.(The default routing will take care of rest)
/Shops/output/somestringhere.
If you have a different name, use that as the query string
public ActionResult output(string name)
{
//do something
}
Now use your form action url like
/Shops/output?name=somestringhere
Another suggestion about your code is to avoid Viewdata for rendering the dropdown. Try to use strongly typed view model and it's properties for transfering data to your view. Also try to move your javascript from your view and make it unobutrusive. So that your view stays as clean markup only.
Assuming you want to show a Revision dropdown in a document create view, Add a property to your viewmodel to have the dropdown items.
public class DocumentCreateViewModel
{
//Other properties also here
public List<SelectListItem> Revisions{ set;get;}
public int SelectedRevision { set;get;}
public DocumentCreateViewModel()
{
Revisions=new List<SelectListItem>();
}
}
and in your GET action, fill the dropdown content to the Revisions property.
public ActionResult Create()
{
var vm=new DocumentCreateViewModel();
vm.Revisions=GetRevisionItemsFromSomeWhere();
return View(vm);
}
And in your strongly typed view,
#model DocumentCreateViewModel
#using(Html.Beginform())
{
#Html.DropDownListFor(x => x.SelectedRevision,
new SelectList(Model.Revisions,"Value","Text"), "Select..")
<input type="submit" />
}
Now to handle the form submit on change event of dropdown, add this script.
$(function(){
$("#SelectedRevision").change(function(){
var _this=$(this);
var selectedRevision=_this.val();
$("form#YourFormIDHere")
.attr("action","./Shops/output/"+selectedRevision).submit();
});
});
Instead of hardcoding the url to shops/output, you may use the razor helper method(#Url.Action) to get the proper path.
#Html.DropDownList(
"revisions", ViewData["revisions"] as SelectList,
new
{
onchange = "submitForm();"
})
and your Javacript goes here
function submitForm()
{
var form = document.forms[0];
form = '/Shops/output?test=test';
form.submit();
}

ViewBag behind the scenes

This is code from the Contoso University online example:
Controller:
[HttpGet]
public ActionResult Edit(int id)
{
Department department = departmentService.GetById(id);
PopulateAdministratorDropDownList(department.PersonID);
return View(department);
}
// POST: /Department/Edit/5
[HttpPost]
public ActionResult Edit(Department department)
{
try
{
if (ModelState.IsValid)
{
departmentService.Update(department);
return RedirectToAction("Index");
}
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem
persists, see your system administrator.");
}
PopulateAdministratorDropDownList(department.PersonID);
return View(department);
}
private void PopulateAdministratorDropDownList(object selectedAdministrator = null)
{
var administrators = instructorService.GetAll().OrderBy(i => i.LastName);
ViewBag.PersonID = new SelectList(administrators, "PersonID", "FullName",
selectedAdministrator);
}
View:
<div class="editor-field">
#Html.DropDownList("PersonID", String.Empty)
#Html.ValidationMessageFor(model => model.PersonID)
</div>
My question is: if in the View we are not accessing the ViewBag.PersonID (we just create a DropDownList, that generates an html select list with the ID="PersonID", without any default selected value), how the hell the ViewBag.PersonID property is binded to that DropDownList? What's happening behind the scenes? This looks like magic!!!
The second question is when Posting the data, I think the controller searches in the view for any html form field whose ID matches a property in the model and that's how we get the selected Department.PersonID on the postback, even if the view code doesn't reference the model (somtheing like model => model.PersonID) right?
Behind the scenes:
The view is calling Html.DropdownList(this HtmlHelper htmlHelper, string name, string optionLabel) which eventually ends up calling SelectExtensions.SelectInternal(htmlHelper, metadata, optionLabel, expression, selectList, allowMultiple, htmlAttributes1) This checks selectList1 for null, and if if it is, it calls SelectExtensions.GetSelectData(htmlHelper, name) which does the magic part of checking the View data for a key matching the name you passed in.
Posting:
Your assumptions here are pretty much right, but the in addition to form fields the framework will also check the query string and route data and any other IValueProvider that is plugged in to the pipe line.

How to keep dropdownlist selected value after postback

In asp.net mvc3 how to keep dropdown list selected item after postback.
Do something Like this :
[HttpPost]
public ActionResult Create(FormCollection collection)
{ if (TryUpdateModel(yourmodel))
{ //your logic
return RedirectToAction("Index");
}
int selectedvalue = Convert.ToInt32(collection["selectedValue"]);
ViewData["dropdownlist"] = new SelectList(getAllEvents.ToList(), "EventID", "Name", selectedvalue);// your dropdownlist
return View();
}
And in the View:
<%: Html.DropDownListFor(model => model.ProductID, (SelectList)ViewData["dropdownlist"])%>
Even easier, you can include the name(s) of your dropdowns in your ActionResult input parameters. Your dropdowns should be in form tags. When the ActionResult is posted to, ASP.Net will iterate through querystrings, form values and cookies. As long as you include your dropdown names, the selected values will be preserved.
Here I have a form with 3 dropdowns that posts to an ActionResult. The dropdown names are (non-case sensitive): ReportName, Year, and Month.
//MAKE SURE TO ACCEPT THE VALUES FOR REPORTNAME, YEAR, AND MONTH SO THAT THEY PERSIST IN THE DROPDOWNS EVEN AFTER POST!!!!
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ReportSelection(string reportName, string year, string month)
{
PopulateFilterDrowdowns();
return View("NameOfMyView");
}
MVC does not use ViewState, which means you will need to manage the value persistence yourself. Typically this is done through your model. So, given that you have a view model, e.g.:
public class MyViewModel { }
And your controller:
public class MyController : Controller
{
public ActionResult Something()
{
return View(new MyViewModel());
}
public ActionResult Something(MyViewModel model)
{
if (!ModelState.IsValid)
return View(model);
return RedirectToAction("Index");
}
}
Now, when you pass the model back to the view with data (probably incorrect - failed validation), when you use your DropDownListFor method, just pass in the value:
#Model.DropDownListFor(m => m.Whatever, new SelectList(...))
... etc.
MVC's model binding will take care of the reading of the data into your model, you just need to ensure you pass that back to the view to show the same value again.
Assuming the selected item is part of the post, the controller now knows what it is. Simply have an entry in the ViewData dictionary indicating which item should be selected (null on get or if nothing was selected). In the view, check the value and if it's not null, select the appropriate option.
Use HttpRequestBase object.
In the view, this should work:
#Html.DropDownList("mydropdown", ViewBag.Itens as IEnumerable<SelectListItem>, new { value = Request["mydropdown"] })
If you are building the drop down list data source in the controller Action Method you can send the selected value to it
Controller:
public ActionResult Index( int serviceid=0)
{
// build the drop down list data source
List<Service> services = db.Service.ToList();
services.Insert(0, new Service() { ServiceID = 0, ServiceName = "All" });
// serviceid is the selected value you want to maintain
ViewBag.ServicesList = new SelectList(services, "ServiceID", "ServiceName",serviceid);
if (serviceid == 0)
{
//do something
}
else
{
// do another thing
}
return View();
}
View:
//ServiceList is coming from ViewBag
#Html.DropDownList("ServicesList", null, htmlAttributes: new { #class = "form-control" })

Resources