unable to bind dropdownlist in mvc using viewmodel property - asp.net-mvc

In my viewmodel I've a getter property as below.
[Display(Name = "Users System:")]
public string UsersSystem { get; set; }
public IEnumerable<SelectListItem> SystemsList
{
get
{
List<SelectListItem> lst = new List<SelectListItem>();
string[] UsersSystem = ConfigurationManager.AppSettings["UsersSystem"].ToString().Split(new char[] { ',' });
foreach (var item in UsersSystem)
{
lst.Add(new SelectListItem { Text = item, Value = item });
}
return lst;
}
}
I need to bind the values to a dropdownlist but I m getting Object reference not set to an instance of an object. My view has the following mark up
#model GazetteerAddressRequest.Lib.Model.ChangeRequestModel
#Html.DropDownListFor(model => model.UsersSystem, Model.SystemsList , new { #class = "form-control" })
Any ideas? thanks

As Stephen has mentioned you can't use the same name for the model property and the SelectList. Add a new property in ChangeRequestModel to hold the value of the selected item in the Dropdown.
public string UserSystemSelected { get; set; }
In your View
#Html.DropDownListFor(model => model.UserSystemSelected, Model.UsersSystem, new { #class = "form-control" })
Here you are populating the dropdown with Model.UsersSystem which has the list of all the SelectListItem and the VALUE SELECTED from the dropdown gets binded to UserSystemSelected.
EDIT:
You can also try this:
In your controller, inside the Action method
ViewBag.SystemList = new SelectList(
ConfigurationManager.AppSettings["UsersSystem"].ToString()
.Split(',')
.Select(x => new KeyValuePair<string, string>(x, x)),"Key", "Value");
And in your View
Html.DropDownListFor(m => m.UserSystemSelected, (SelectList)ViewBag.SystemList)

You have to pass the model into view, otherwise the model will be null in view.
Eg. first you can pass the SelectListItem list into ChangeRequestModel and then that into the view.
public ActionResult YourPage(){
return View(changeRequestModel);
}

Related

Select default value for DropDownListFor using ViewBag as SelectList

In my controller I have a list of Agents stored in ViewBag
ViewBag.Agents = new SelectList(db.Users.ToList(), "Id", "UserName", string.Empty);
In my View I have display this as a DropDownListFor
#Html.DropDownListFor(model => a.AgentList, ViewBag.Agents as SelectList, new { #class = "form -control", #style = "width:130px; height:30px" })
However, my list is not showing the already selected Agent as Default. What am I missing? How can I set the Dropdownlist to display selected Agent as default?
I even tried this but nothing work:
#Html.DropDownListFor(model => a.AgentList, new SelectList( ViewBag.Agents as SelectList, a.AgentName), new { #class = "form -control", #style = "width:130px; height:30px" })
Here is my model
[Display(Name = "Agent ID")]
public string AgentID { get; set; }
[Display(Name = "Agent Name")]
public string AgentName { get; set; }
[Display(Name = "Agent")]
public List<ApplicationUser> AgentList { get; set; }
Thank you for helping
Please use the below step for bind the selected value in DropDownListFor.
Step:- 1 ViewBag.Agents= db.Users.ToList();
Step:- 2 #Html.DropDownListFor(model => Model.AgentID, new SelectList(ViewBag.Agents, "Id", "UserName",2))
Try:
#Html.DropDownListFor(model => a.AgentList, new SelectList( ViewBag.Agents, Model.AgentName), new { #class = "form -control", #style = "width:130px; height:30px" })
Hi you make use of this overload of selectlist
SelectList Constructor (IEnumerable, String, String, Object)
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField,
object selectedValue
)
It will initializes a new instance of the SelectList class by using the specified items for the list, the data value field, the data text field, and a selected value.
So you code will change like:
ViewBag.Agents = new SelectList(db.Users.ToList(), "Id", "UserName", 10 /*Default user Id*/);
What I have found, is that if the form is bound to a Model, the model value (which is probably null by default) will override whatever selected value is set by the ViewBag List. So, it is best to set the default value inside the model.
For example:
[ViewModel for the form] ModelFormType ViewModel = new ModelFormType();
ModelFormType.UserId = 11 (default user Id).

Issue with Model Binding

I have created a View Model called CompetitionRoundModel which is partially produced below:
public class CompetitionRoundModel
{
public IEnumerable<SelectListItem> CategoryValues
{
get
{
return Enumerable
.Range(0, Categories.Count())
.Select(x => new SelectListItem
{
Value = Categories.ElementAt(x).Id.ToString(),
Text = Categories.ElementAt(x).Name
});
}
}
[Display(Name = "Category")]
public int CategoryId { get; set; }
public IEnumerable<Category> Categories { get; set; }
// Other parameters
}
I have structured the model this way because I need to populate a dropdown based on the value stored in CategoryValues. So for my view I have:
#using (Html.BeginForm())
{
<div class="form-group">
#Html.LabelFor(model => model.CategoryId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.CategoryId, Model.CategoryValues, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CategoryId, "", new { #class = "text-danger" })
</div>
</div>
// Other code goes here
}
I have selected model.CategoryId in the DropDownListFor() method since I want to bind the selected value to CategoryId. I really don't care for CategoryValues, I just need it to populate the DropDown.
My problem now is that when my Controller receives the values for my Model in the action method, CategoryValues is null which causes the system to throw a ArgumentNullException (the line that is highlighted is the return Enumerable line.
I have even tried [Bind(Exclude="CategoryValues")] but no change at all. Any help would be much appreciated.
Your not (and should not be) creating form controls for each property of each Category in your IEnumerable<Category> collection so in your POST method, the value of Categories is null (it never gets initialized). As soon as you attempt CategoryValues and exception is thrown by your .Range(0, Categories.Count()) line of code in the getter.
Change you view model to give CategoryValues a simple geter/setter, and delete the Categories property
public class CompetitionRoundModel
{
public IEnumerable<SelectListItem> CategoryValues { get; set; }
[Display(Name = "Category")]
public int CategoryId { get; set; }
.... // Other properties
}
and populate the SelectList in the controller methods, for example
var categories db.Categories; // your database call
CompetitionRoundModel model = new CompetitionRoundModel()
{
CategoryValues = categories.Select(x => new SelectListItem()
{
Value = x.Id.ToString(),
Text = x.Name
},
....
};
return View(model);
or alternatively
CompetitionRoundModel model = new CompetitionRoundModel()
{
CategoryValues = new SelectList(categories, "Id", "Name" ),
Note also that if you return the view (because ModelState is invalid, the you need to repopulate the value of CategoryValues (refer The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable' for more detail)
Since CategoryValues just populates the drop down, it will never post back to the server and you'll need to rebuild the list from the database before using it in the GET or POST operation. The CategoryId property is the value that will be posted back to the server from the DropDownList.

How to populate Dropdowlistfor in ASP.NET MVC with Entity Framework

VIEW
#Html.DropDownListFor(model => model.SupplierId,
new SelectList(new Pharmacy_Project.Models.Supplier().SupplierList, "Value", "Text"),
new { #class = "form-control" })
Controller
public IEnumerable<SelectListItem> SupplierList
{
get
{
using (var db = new DatabaseContext())
{
var list = (from s in db.Suppliers select s).Select(x => new SelectListItem
{
Text = x.SupplierName,
Value = x.SupplierId.ToString()
});
return list;
}
}
}
Error:
The operation cannot be completed because the DbContext has been disposed.
I tried to change return list.Tolist(); but I then encounter this error:
LINQ to Entities does not recognize the method 'System.String
ToString()' method, and this method cannot be translated into a store
expression.
You need to materialize you query first using .ToList() (or AsEnumerable())
var list = (from s in db.Suppliers select s).ToList().Select(x => new SelectListItem{ ... }
Side note: You have already created IEnumerable<SelectListItem> so ceating another identical IEnumerable<SelectListItem> in the view is pointless extra overhead and you view should be just
#Html.DropDownListFor(model => model.SupplierId, Pharmacy_Project.Models.Supplier().SupplierList, new { #class = "form-control"})
or better still, use a view model with a property public IEnumerable<SelectListItem> SupplierList { get; set; } and populate it in the controller before you send it to the view, so that the view is
#Html.DropDownListFor(model => model.SupplierId, Model.SupplierList, new { #class = "form-control"})
Note also that you can also use new SelectList(db.Suppliers, "SupplierId", "SupplierName") to generate the SelectList

Client side validation doesn't work for the dropdown

View
#Html.DropDownListFor(m => m.InsertCustomer.CountryID, Model.lstCountry, new { #class = "DropDownListFor" })
#Html.ValidationMessageFor(m =>m.InsertCustomer.CountryID)
View Model
[Required(ErrorMessage = "Please Select Country")]
public string CountryID { get; set; }
Method to create a list for the dropdown
public IEnumerable<SelectListItem> getCountry()
{
DNC_DAL.clsCustomerMaster _objDalUser = new DNC_DAL.clsCustomerMaster();
DataTable dtCountry = new DataTable();
dtCountry = _objDalUser.GetCountry();
List<SelectListItem> lstCountry = new List<SelectListItem>();
SelectListItem firstOption = new SelectListItem() { Text = "---Select One---" };
lstCountry.Add(firstOption);
foreach (DataRow drCountry in dtCountry.Rows)
{
SelectListItem Country = new SelectListItem() { Text = drCountry["DCM_DESC"].ToString(), Value = drCountry["DCM_ID"].ToString() };
lstCountry.Add(Country);
}
return lstCountry;
}
Controller
public ActionResult wfrmCustomerMaster()
{
Models.clsCustomerMaster CustomerModel = new Models.clsCustomerMaster();
IEnumerable<SelectListItem> strCountry = null;
strCountry = CustomerModel.getCountry();
CustomerModel.lstCountry = strCountry;
return View(CustomerModel);
}
All the other validations( Not posted in the question) work perfectly on the page except for the dropdown validation, I wonder why?
Your code is adding the first option as
<option>---Select One---</option>
which does not have a value="" attribute, which means if you select it, the value of the <select> element will be "---Select One---", which is valid (i.e. its not null or an empty string).
Instead, to generate a label option with a null value, use the overload that accepts a optionLabel, which will generate the first option as
<option value="">---Select One---</option>
and remove the code in the getCountry() which generates this option

How to work with DropDownListFor in an EDIT view

Hi I have a problem with DropDownListFor on the Edit view.
Basically I'm using a partial view which contains my form and in my Edit and Create view I call this partial view.
I have around 5 similiar DropdownlistFor and these work well on create action but in edit doesn't, mainly i'm not getting (unable) to set the selected value.
In my Edit Action (GET), I fill my property ViewModel if the true object has the property filled.
if(icb.BAOfficer != null)
editICB.BAOfficer = icb.BAOfficer;
List<Staff> staffs = _fireService.GetAllStaffs().ToList();
staffs.Insert(0, new Staff { StaffId = -1, Name = "" });
editICB.BAOfficers = staffs;
return View(editICB);
This is how I'm filling my drop down and how I'm trying to set the selected value.
#Html.DropDownListFor(model => model.BAOfficerSelected, new SelectList(Model.BAOfficers, "StaffId", "Name", (Model.BAOfficer!= null ? Model.BAOfficer.StaffId:-1)), new { #class = "rounded indent" })
#Html.ValidationMessageFor(model => model.BAOfficer.StaffId)
I solve the problem setting a value to my model.BAOfficerSelected in Edit Action, this was the (easy) secret.
I need the first item like a empty option because is not a required information, but on the edit view if has value I need to set it as selected option.
In the end, it was my code.
My Model
public int BAOfficerSelected { get; set; }
public SelectList BAOfficers { get; set; }`
My Controller Create/Edit Action
if (icb.BAOfficer != null) // only for edit action
editICB.BAOfficerSelected = icb.BAOfficer.StaffId; //this will set the selected value like a mapping
//for Edit and Create
List<Staff> staffs = _fireService.GetAllStaffs().ToList();
staffs.Insert(0, new Staff { StaffId = -1, Name = "" });
editICB.BAOfficers = new SelectList(staffs, "StaffId", "Name");
return View(editICB);`
My View
#Html.DropDownListFor(model => model.BAOfficerSelected, Model.BAOfficers, new { #class = "rounded indent" })
I hope this can help others.
The best and cleanest way of doing this is setting the selected value in server side, in the SelectList object.
So, if your BAOfficerSelected is nullable... it is all simpler: You don't need to rely in adding a dummy item to hold the -1 for not selected value.
Instead, you do it this way:
List<Staff> staffs = _fireService.GetAllStaffs().ToList();
editICB.BAOfficers = new SelectList(staffs, "StaffId", "Name", editICB.BAOfficer != null ? editICB.BAOfficer.StaffId : null);
Of course, the BAOfficers need to be changed type from List<Staff> to SelectList.
Then, in your partial view you do:
#Html.DropDownListFor(model => model.BAOfficerSelected, Model.BAOfficers, "Select one...", new { #class = "rounded indent" })
Adding the 3rd parameter is needed to indicate that the default value (if nothing is selected) is that text.
Instead of using a SelectList, I often find it works better to use a List<SelectListItem>.
Further, I usually use an EditorTemplate for my dropdowns to keep my views clean.
So if my select list returns List<SelectListItem>:
public List<SelectListItem> BAOfficers { get; set };
You can set it up like this:
model.BAOfficers = staffs.Select(staff =>
new SelectListItem { Text = staff.Name, Value = staff.StaffId }).ToList();
Then in your EditorTemplate:
<!-- EditorTempaltes\DropDownList.cshtml -->
#model System.String
<p>
#Html.LabelFor(m => m):
#Html.DropDownListFor(m => m, new SelectList(
(List<SelectListItem>)ViewData["selectList"], "Value", "Text",
String.IsNullOrEmpty(Model) ? String.Empty : Model), String.Empty)
#Html.ValidationMessageFor(m => m)
</p>
And then in the view, just pass the SelectList into the EditorTemplate:
#Html.EditorFor(m => m.BAOfficerSelected, "DropDownList",
new { selectList = Model.BAOfficers() })
I met the same problem ,too.
According the article https://dotnetfiddle.net/PIGNLF which way gave a simple way to deal with this problem without two Models or more classes.enter link description here
here is my code
add model
public class NoteSelectLisModel
{
public string Value { get; set; }
public string Name { get; set; }
}
add Controller
public ActionResult Edit(int? _ID)
{
ViewBag.NoteState = new SelectList(new List<NoteSelectLisModel>()
{
new NoteSelectLisModel() {Value="1",Name="A)"},
new NoteSelectLisModel() {Value="2",Name="B"},
new NoteSelectLisModel() {Value ="3",Name ="C"}
}, "Value", "Name", 1);
Table ut = _db.Tables.Find(_ID);
if (ut == null)
{
return HttpNotFound();
}
else
{
return View(ut);
}
}
add View .cshtml
#Html.DropDownListFor(m => m.NOTE, (IEnumerable<SelectListItem>)ViewBag.NoteState, "No Selected")
The edit's Model is the same and the dropdownlist passed by View.bag

Resources