System.NullReferenceException in mvc partial view when passing a list - asp.net-mvc

I am trying to add a list in search box in partial view, but I am always getting System.NullReferenceException. A similar option is working when I keep as a separate view. I am not what I am doing wrong when passing List?
Following is the snippet from views and controllers:
1] _layout.cshtml:
<div class="row">
#Html.Partial("SearchBarPartial2", Model)
</div>
2] SearchPartialView2.cshtml:
<div class="form-group">
#using (Html.BeginForm("SearchBarPartial2", "Search"))
{
#Html.LabelFor(m => m.CompanyList, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownListFor(
m => m.CompanyList,
new SelectList(Model.CompanyList, "fldt", "Value", Model.CompanyList.First().Value),
new { #class = "form-control" }
)
</div>
}
</div>
3] SearchController.cs:
public ActionResult SearchBarPartial2(cmpnytable cmpnytable1)
{
List<Company> objcompany = new List<Company>();
objcompany = GetCompanyList();
SelectList objlistofcompanytobind = new SelectList(objcompany, "ID", "Name", 0);
cmpnytable1.CompanyList = objlistofcompanytobind;
return View(cmpnytable1);
}

Your drop down list declaration already shown evidence of the error:
#Html.DropDownListFor(m => m.CompanyList, new SelectList(Model.CompanyList, "fldt", "Value", Model.CompanyList.First().Value), new { #class = "form-control" })
As Stephen said, you're assigned the model binding expression pointed to CompanyList, which becomes the source of all option tags to be rendered. It has no sense to pass the SelectList items as both binding target and source of the option list.
To resolve this issue, place additional model property with integer/string type for holding DropDownList selection result as this:
// Model
public class cmpnytable
{
// other properties here
public int SelectedId { get; set; }
}
// View
#model myproj.Models.cmpnytable
#Html.DropDownListFor(m => m.SelectedId, Model.CompanyList, new { #class = "form-control" })
Since CompanyList itself passed to view as SelectList, it's no use to create new instance of SelectList on the view.

Related

DropDown Population Error in ASP.NET MVC 5

I have the following in my controller:
public ActionResult Create()
{
ViewBag.PlayerId = new SelectList(db.Players, "Id", "Name");
return View();
}
This is in the view:
<div class="form-group">
#Html.LabelFor(model => model.PlayerId, "PlayerId", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("PlayerId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.PlayerId, "", new { #class = "text-danger" })
</div>
</div>
But when I submit the form, it gives me the below error:
System.InvalidOperationException: 'The ViewData item that has the key 'PlayerId' is of type 'System.Int32' but must be of type 'IEnumerable'.'
I googled a lot but were not able to find the solution. Your help is highly appreciated.
Write your #Html.DropDownList as follows:
#Html.DropDownList("PlayerId", ViewBag.PlayerId as SelectList,"Select Player", htmlAttributes: new { #class = "form-control" })
Now it will work!
You have to pass the SelectList into dropdown but actually the model binder is confused between PlayerId as viewmodel property and PlayerId as ViewBag property, hence causing the error.
Better to create a viewmodel property which will store option list with different name:
public class ViewModel
{
public int PlayerId { get; set; }
// other properties
// option list here
public List<SelectListItem> PlayerList { get; set; }
}
Then add the option lists from database into controller action:
public ActionResult Create()
{
var model = new ViewModel();
model.PlayerList = db.Players.Select(x => new SelectListItem { Text = x.Name, Value = x.Id }).ToList();
return View(model);
}
And use strongly-typed helper to bind it afterwards:
#Html.DropDownListFor(model => model.PlayerId, Model.PlayerList, "Select", new { #class = "form-control" })
Related issue:
The ViewData item that has the key is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'

Html Helper Drop Down List switches value to top option on submit / in database

I am filling out a form, however when selecting an option from the drop down list and click submit, no matter what option I select, it always parses the top one through. The displayed value never changes, so it you leave it as the default option 'please select...' and click submit, this stays as 'please select...' but the entry in the database is always the one that appears at the top of the drop down.
Here is the model:
public enum Medium
{
[Description("Teleconference & Report")]
Teleconference_Report,
[Description("Email & Telephone")]
Email_Telephone
}
[Required]
[Display(Name = "Medium")]
public Medium Medium { get; set; }
Here is the field in the form:
<div class="form-group">
#Html.LabelFor(model => model.Medium, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.DropDownList("MediumID", null, "Please select...", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Medium, "", new { #class = "text-danger" })
</div>
</div>
The "MediumID" DropDownList is populated using a viewbag which is set to whatever the following returns:
// Puts all of the mediums of communication into a user friendly dropdownlist.
public List<SelectListItem> GetMediumList()
{
List<SelectListItem> mediumList = new List<SelectListItem>();
foreach (Medium state in EnumToList<Medium>())
{
mediumList.Add(new SelectListItem
{
Text = GetEnumDescription(state),
Value = state.ToString(),
});
}
return mediumList;
}
Below shows the form section for another enum called 'Frequency', but these are not changed to user friendly strings (and is working fine).
<div class="form-group">
#Html.LabelFor(model => model.Frequency, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.EnumDropDownListFor(model => model.Frequency, "Please select...", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Frequency, "", new { #class = "text-danger" })
</div>
</div>
Below here, shows the two methods which turn the enums into user friendly strings:
// Returns a 'user friendly', readable version of the enum.
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
// Puts all of the same enums into a list.
public static IEnumerable<T> EnumToList<T>()
{
Type enumType = typeof(T);
// Can't use generic type constraints on value types,
// so have to do check like this.
if (enumType.BaseType != typeof(Enum))
throw new ArgumentException("T must be of type System.Enum");
Array enumValArray = Enum.GetValues(enumType);
List<T> enumValList = new List<T>(enumValArray.Length);
foreach (int val in enumValArray)
{
enumValList.Add((T)Enum.Parse(enumType, val.ToString()));
}
return enumValList;
}
Finally, here is the method signature where the fields are binded/bound:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Point,ApplicationID,MediumID,Frequency,StartDate,EndDate")] TouchPoint touchPoint)
Within this method, the dropdown is passed to the view using the following:
ViewBag.MediumID = GetMediumList();
Any help is greatly appreciated.
Your model has a property named Medium but your view does not bind to that property. The name of the <select> your generating is MediumID which does not exist in your model, so the default value for Medium when you submit will Teleconference_Report (the first enum value).
Change the view to
#Html.DropDownListFor(m => m.Medium, (IEnumerable<SelectListItem>)ViewBag.MediumID, "Please select...", new { #class = "form-control" })
although I would recommend changing the ViewBag property name to say MediumList to make it more obvious that its a collection. And even better, use a view model with a property public IEnumerable<SelectListItem> MediumList { get; set; } so that the viewcan be #Html.DropDownListFor(m => m.Medium, Model.MediumList, .... ).
You also need to change the [Bind] attribute to include "Medium" (and remove "MediumID") although using a view model means the [Bind] attribute is not required.
Side note: You do not need the [Required] attribute unless you want to add a specific error message using the ErrorMessage = "..." property (an enum is always required by default unless you make the property nullable).

Remove MVC 5 EditorTemplate additional ID

I am using this Editor Template for Dropdownlist with ViewBag/ViewData of same property Name
#model System.String
#*
For Using this Editor Template
- There should be a viewbag/viewdata (type SelectList) of same name as of calling Model's Property
*#
#{
var modelMetadata = ViewData.ModelMetadata;
// Get property name of the model
var propertyname = modelMetadata.PropertyName;
}
#if (ViewData[propertyname] == null)
{
#Html.DropDownList(propertyname , Enumerable.Empty<SelectListItem>(), "--Select--", new { #class = "form-control" })
}
else
{
#Html.DropDownList(propertyname , null, "--Select--", new { #class = "form-control" })
}
now using it as
#Html.EditorFor(i=>i.Country,"CustomDropDown")
I also have a ViewBag.Country as SelectList of countries.
Everything works fine, but now the Naming of the Control becomes
<select class="form-control" id="Country_Country" name="Country.Country">
how to remove the additional Country from the id and name?
Additional Info:
I could have just used the #Html.DropDownList("Country") but it doesn't allow me to add the css class to the control.
I think i found the Solution.
I changed the DropDownList to DropDownListFor with some changes
#if (ViewData[propertyname] == null)
{
#Html.DropDownListFor(m=>m, Enumerable.Empty<SelectListItem>(), "--Select--", new { #class = "form-control" })
}
else
{
#Html.DropDownListFor(m => m, ViewData[propertyname] as SelectList, "--Select--", new { #class = "form-control" })
}
this auto ViewData bind is kind of confusing at times. >_<

MVC4 SelectList not selected default object

My select list isn't selecting the default object being brought in through code.
I first create my SelectList like so:
public SelectList CreateSelectList(object objSelected = null)
{
return new SelectList(GetAll().OrderBy(s => s.NumericalValue), "PeriodID", "Name", objSelected);
}
My objSelected gets filled with a Guid that's associated with the PeriodID.
Inside my controller I define my viewbag variable to the new select list.
public ActionResult Edit(Guid id)
{
Classroom classroom = classroomRepository.GetByID(id);
ViewBag.PeriodID = periodRepository.CreateSelectList(classroom.PeriodID);
return View(classroom);
}
Then in my View here's how I'm displaying my SelectList:
<div class="control-group">
#Html.LabelFor(model => model.PeriodID, "Period", new { #class = "control-label" })
<div class="controls">
#Html.DropDownListFor(model => model.PeriodID, ViewBag.PeriodID as SelectList, String.Empty, new { #class = "span3" })
#Html.ValidationMessageFor(model => model.PeriodID)
</div>
</div>
You have two problems here. First, this:
#Html.DropDownListFor(model => model.PeriodID, ViewBag.PeriodID as SelectList,
String.Empty, new { #class = "span3" })
Change ViewBag.PeriodID to ViewBag.Periods or ViewBag.PeriodList. This is confusing, and there are a number of situations in which MVC will get confused if you use the same named object. It's just best to make sure everything is named differently.
Second, The SelectList class ignores the selecteditem member of the SelectListItem. It's not used at all. DropDownListFor will take the value of model.PeriodID and make it the selected value. However, I see in your code that those should be the same so I'm guessing the naming may be a factor here.

DataBinding: 'System.Web.Mvc.SelectListItem' does not contain a property with the name 'CategoryTypeID'

I am using MVC. I want to pass the category data I entered from my view and passed to my Post/ Createcontroller, but it's not's letting me pass my categoryTypeID that I have selected from my dropdownlist.
Here is the error:
DataBinding: 'System.Web.Mvc.SelectListItem' does not contain a property with the name 'CategoryTypeID'.
Here is my code:
My CreateController:
//
// POST: /Category/Create
[HttpPost]
public ActionResult Create(Category category)
{
if (ModelState.IsValid)
{
db.Categories.Add(category);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CategoryTypes = new SelectList(db.CategoryTypes, "CategoryTypeID", "Name", category.CategoryTypeID);
return View(category);
}
My Create View
#model Haykal.Models.Category
<div class="editor-label">
#Html.LabelFor(model => model.CategoryTypeID, "CategoryType")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.CategoryTypeID,
new SelectList(ViewBag.CategoryTypes as System.Collections.IEnumerable, "CategoryTypeID", "Name"),
"--select Category Type --", new { id = "categoryType" })
#Html.ValidationMessageFor(model => model.CategoryTypeID)
</div>
I faced this error. I was binding an object of the View Model:
editPanelViewModel.Panel = new SelectList(panels, "PanelId", "PanelName");
In the View, I created the ListBox like this:
#Html.ListBoxFor(m => m.Panel, new SelectList(Model.Panel, "PanelId", "PanelName"))
It should be like this in fact:
#Html.ListBoxFor(m => m.Panel, new SelectList(Model.Panel, "Value", "Text"))
You are defining your SelectList twice, in your controller as well as in your view.
Keep the view clean. Just the following would be enough in your case:
#Html.DropDownListFor(model => model.CategoryTypeID, (SelectList)ViewBag.CategoryTypes)
I have to admit that DropDownListFor is quite confusing in the beginning :)

Resources