I know it was silly to ask this question but I'm not able to figure it out and I need your help guys.
First of all I am new to MVC. In my Project I am using a dropdownlistFor helper for displaying a list of names available for a particular Id. I did that and it is displaying names for an id.
Now while posting the form I am getting a Null Reference Exception for property used in the dropdownlist.
Here is my property in model which is a list of names.
In my controller in the [HttpGet] I did this which calls a function and returns a list of names for that Id.
Now the list of names is being displyed while form loading. And my view is as
When I am submitting the form I am getting a Null Reference Exception because in new SelectList(Model.InterviewerName) the Model is NULL.
Is there anyway to get me out of this issue.
I think you should update your viewmodel like this:
public class InterviewViewModel
{
public List<SelectListItem> Interviewers { set;get;}
public int SelectedInterviewerID { set;get;}
//Other properties relevant to the view as needed
}
And in your GET action set the Interviewers collection property:
public ActionResult Interview()
{
var vm=new InterviewViewModel();
vm.Interviewers =GetInterViewrsFromSomewhere();
return View(vm);
}
public List<SelectListItem> GetInterViewrsFromSomewhere()
{
var list=new List<SelectListItem>();
//Items hard coded for demo. you can read from your db and fill here
list.Add(new SelectListItem { Value="1", Text="AA"});
list.Add(new SelectListItem { Value="2", Text="BB"});
return list;
}
And in your view which is strongly typed to InterviewViewModel
#model InterviewViewModel
#using(Html.Beginform())
{
<p>Select interviewer :
#Html.DropdownlistFor(x=>x.SelectedInterviewerID,Model.Interviewers,"Select")
<input type="submit" />
}
So when the form is posted, The selected interviewers id will be available in the SelectedInterviewerID property:
[HttpPost]
public ActionResult Interview(InterviewViewModel model)
{
if(ModelState.IsValid)
{
//check for model.SelectedIntervieweID value
//to do :Save and redirect
}
//Reload the dropdown data again before returning to view
vm.Interviewers=GetInterViewrsFromSomewhere();
return View(vm);
}
In the HttpPost action method, if you are returning the viewmodel back to the view, you need to refill the dropdown content because HTTP is stateless and it won't keep the dropdown content between the requests (Webforms does this using Viewstate and here in MVC we don't have that).
I think i spotted the problem, you need to do the following two things to resolve,
1) change the model property public IList<string> InterviewerName to public string InterviewerName
2) use ViewBag to take the selectlist values to the View.
Let me know if it helps.
Related
I'm obviously missing something.
I thought populating a DropDownListFor would be as easy as returning a list from the controller.
In my controller I return:
public ActionResult ListCollege()
{
return View(db.Colleges.ToList());
}
And the in the View I set the model as:
#model IEnumerable<CollegeApp.Models.DataModels.College>
But that's clearly not the right way to populate a DropDownListFor helper.
I've been doing a bit of reading and I wasn't exactly sure of the role of the new SelectList as the second argument in the DropDownListFor which is meant to be of type IEnumerable<SelectListItem>.
And I don't quite get how this IEnumerable<SelectListItem> is passed from the model/controller to the view.
Thanks
To use The DropDownListFor helper method effectively, you need to use a property of your view model to pass as the expression parameter, which will be a lambda expression. The helper will build the SELECT element with name and Id attribute values matching to that property name. The second parameter of the helper is a collection of SelectListItem , which will be used as the source data to build the options for the dropdown.
So in your case, create a view model which has 2 properties, one for the collection and one for the selected value
public class CollageSelectionVm
{
public IEnumerable<SelectListItem> Collages { set;get;}
public int SelectedCollage { set;get;}
}
And in your GET action, create an object of this view model, load the Collages collection property and send that object to the view
public ActionResult ListCollege()
{
var vm = new CollageSelectionVm () ;
vm.Collages = db.Collages
.Select(x=>new SelectListItem { Value = x.Id.ToString(),
Text=x.Name })
.ToList();
return View(vm);
}
Now in the view,which is strongly typed to your view model, you will use the DropDownListFor helper
#model CollageSelectionVm
#Html.DropDownListFor(a => a.SelectedCollage , Model.Collages , "Select one")
my view:
#using (Html.BeginForm("Index", "Person"))
{
#Html.DropDownList("Departments",ViewData["Departments"] as SelectList)
<button type="submit">Select</button>
}
my DepartmentController:
public ActionResult Index()
{
ViewData["Departments"] = new SelectList(db.Departments, "ID", "Name");
return View();
}
my PersonController
public ActionResult Index(string id = null)
{
if (id != null)
{
//Return list of persons with department id
}
return View();
}
My problem:
When I select a department from the DropDown and press the button, it redirects fine, but the id is not passed.
What am I missing? I'm guessing it has to do with how i fill the DropDownList?
Anyway, as always, thanks in advance
The name attribute of your dropdown is not "id" so the MVC model binder can not bind it.
Add html attribute new {#Name ='id'} to your DropDown definition and it should work.
I also would suggest that your view receive a model - in this case model binding will be much easier, and you could use DropDownFor helper.
Using model also allows you to avoid using ViewData and ViewBag containers that are not recommended because they are not strongly typed so if by mistake you write ViewData["Departnents"] in your View you won't get a compilation error because of the typo, but clearly it won't work.
As an opposite you can define a model
public class Person
{
public SelectList Departments {get; set;}
public int SelectedDepatrmentId {get; set;}
//Other person properties come here
}
In your View the only thing you should do to make it work is:
#model path to your Person class
#Html.DropDownListFor(model => model.SelectedDepatrmentId, Model.Departments)
The problem in your case that mvc model binding is done with name attribute and #Html.DropDownList("Departments"... will render html with dropdown having name 'Departments' so either try my first answer or change #Html.DropDownList("Departments"... as shown in my second answer.
Try This :
public ActionResult Index(string Departments) // <------ Use 'Departments' here instead of 'id'
{
.....
return View();
}
OR change dropdownlist as :
#Html.DropDownList("id",ViewData["Departments"] as SelectList)
I'm fairly new to ASP.NET MVC and while I'm aware that ignorance isn't an excuse I couldn't find any helpful(to me) answers from similar questions.
Issue:
My ModelState is invalid because I've bound the id of the RoleDTO model( a model in a partial view which is in begincollectionitem ) to the dropdownlist using Html.DropDownListFor( r => r.Id, ((IEnumerable<SelectListItem>)ViewBag.PossibleRoles)). Because of that the Name property of the RoleDTO model is always empty and ModelState validation fails. How do I handle this situation properly?
Details:
I've got User and Role models with N-N relationship, and their DTOs.
I've got a UserController wherein I've got create/edit actions. Here's how Edit GET and POST actions look:
[HttpGet]
public ActionResult Edit(int id)
{
var model = userRepository.Get(id);
LoadPossibleRoles();
return View(model);
}
[HttpPost]
public ActionResult Edit(UserDTO model)
{
if (ModelState.IsValid)
{
userRepository.InsertOrUpdate(model);
userRepository.Save();
return RedirectToAction("Index");
}
else
{
LoadPossibleRoles();
return View(model);
}
}
What LoadPossibleRoles() does is retrieve all roles from the repository, convert them to SelectListItems and puts them in the viewbag(I should probably create a viewmodel or something but I'm unsure how to create/use one in my situation). It looks like this:
private void LoadPossibleRoles()
{
var availableRoles = roleRepository.GetAll();
var selectItems = new List<SelectListItem>();
foreach (var role in availableRoles)
{
var listItem = new SelectListItem();
listItem.Value = role.Id.ToString();
listItem.Text = role.Name;
selectItems.Add(listItem);
}
ViewBag.PossibleRoles = selectItems;
}
I've got a _CreateOrEdit partial view whose model is UserDTO In which I've got _SingleRoleEdit partial for each added role. It looks like this:
Add a role
#foreach( var r in Model.Roles)
{
#Html.Partial("_SingleRoleEdit", r)
}
The insertNewRole() js function is an ajax call which calls "CreateNewRole" method in the UserController. The method looks like this:
public PartialViewResult CreateNewRole()
{
LoadPossibleRoles();
return PartialView("_SingleRoleEdit", new RoleDTO());
}
And finally in _SingleRoleEdit partial I generate the dropdown list for all available roles:
#using (Html.BeginCollectionItem("Roles"))
{
<table class="editor-table">
<tr>
<th>Role</th>
<td>#Html.DropDownListFor( r => r.Id, ((IEnumerable<SelectListItem>)ViewBag.PossibleRoles))</td>
<td>X</td>
</tr>
</table>
}
Presentationally this works as it should. I can add/remove dropdownlists which actually do show all available roles. The 'issue' is the way the data binding currently works. DropDownListFor binds the selected value in the dropdownlist to the models Id, however there is currently nothing binding the name to the text of the dropdownlist and that's why my ModelState is always invalid on Post. I'm aware that binding the text of the selection in the dropdownlist to the model is a bad idea. So I'm looking for a proper way to handle this situation.
In MVC4:
I have the following property in my model used for a dropdown list:
public SelectList Subjects { get; set; }
I set the Subjects property in my Index() Action on page load and return the model.
The dropdown gets populated just fine with the SelectListItems.
#Html.DropDownListFor(x => x.Subject, new SelectList(Model.Subjects, "Text", "Text", "Other"))
When I submit the form the Subjects SelectList in the model has changed to null. There has to be a simple way to persist this on HttpPost. I assume I want to submit and post this SelectList as well, along with all the form fields? How would I do this?
It is commonly accepted that you re-populate a SelectList after the Post action. Just extract it inside a method and call it in the Get and Post action.
Posting it back again to the controller is not the way to go. You can cache the items in the SelectList so you won't have to make a query to the data store twice.
Example:
public ActionResult Create()
{
var model = new SubjectModel();
PopulateSubjectList(model);
return View(model);
}
[HttpPost]
public ActionResult Create(SubjectModel model)
{
if (ModelState.IsValid)
{
// Save item..
}
// Something went wrong.
PopulateSubjectList(model);
return View(model);
}
private void PopulateSubjectList(SubjectModel model)
{
if (MemoryCache.Default.Contains("SubjectList"))
{
// The SubjectList already exists in the cache,
model.Subjects = (List<Subject>)MemoryCache.Default.Get("SubjectList");
}
else
{
// The select list does not yet exists in the cache, fetch items from the data store.
List<Subject> selectList = _db.Subjects.ToList();
// Cache the list in memory for 15 minutes.
MemoryCache.Default.Add("SubjectList", selectList, DateTime.Now.AddMinutes(15));
model.Subjects = selectList;
}
}
Note: MemoryCache uses the System.Runtime.Caching namespace. See: System.Runtime.Caching namespace.
Also, caching should be in a seperate layer between your controller (or business layer) and the data access layer, this is just for clarity.
Browsers only post back the selected values on the form elements. Also, its not a good idea to post back the values which can be retrieved from the data store. You would have to pull the items in the list just like you did while populating the list.
Also, MVC does not maintain the state of the page like .NET webpages as it does not have a view state. Developers are fully responsible for managing states of pages between the post backs, which is the essence of MVC design pattern.
i want to show a dropdownList on a page using Entity Framework in my MVC app, but i am just stuck here to do this using using HTML Helper. so if anyone having knowledge of entity framework, help me...
my dataContext partial class is Entities, in which an entity named MemberInfo have some fields including MemberID & MemberName, so my dropdownList should show the field MemberName & behind this the value should be MemberID,
the code i tried yet--->
#Html.DropDownListFor(Model => Model.MemberID, MemberInfo)
in controller i am returning the Model--->
var MemberNameList = FinanceDBContext.MemberInfoes.Select(x => new { x.MemberID, x.Name });
return View(MemberNameList);
but its not working (errors).
You need to pass in all of your objects as the "model". Best practice is to use a ViewModel which will contain the list of data and a property to store the selected item.
ViewModel
public class MyViewModel
{
// The drop-down list and variable to get selection
public List<Member> Members { get; set; }
public int SelectedMemberId { get; set; }
}
Controller
[HttpGet]
public ActionResult Index()
{
var viewModel = new MyViewModel();
viewModel.Members = FinanceDBContext.MemberInfoes.ToList();
return View(viewModel);
}
[HttpPost]
public ActionResult Index(MyViewModel viewModel)
{
string debug = string.Format("You selected member: {0}", viewModel.SelectedMemberId);
return View(viewModel);
}
Finally, in your view (these lines need to be inside a BeginForm { ... } and ensure your View is strongly typed to MyViewModel
#Html.DropDownList("SelectedMemberId", new SelectList(Model.Members, "MemberID", "Name"))
<input type="submit" value="Save etc..." />
In this example you could put a break-point on the HttpPost action and check the debug string to check the correct Member is returned and proceed as required.