This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
This model is used to define a view:
namespace OnlineStore.ViewModels
{
public class SubCategoryVM
{
[Key]
public int ID { get; set; }
[Required]
public virtual string Name { get; set; }
[Required(ErrorMessage = "Parent Category Name is required")]
public virtual string ParentName { get; set; }
public IEnumerable<SelectListItem> categoryNames { get; set; }
}
}
Inside controller:
public ActionResult createSubCategory()
{
SubCategoryVM model = new SubCategoryVM();
var cNames = db.Categories.ToList();
model.categoryNames = cNames.Select(x
=> new SelectListItem
{
Value = x.Name,
Text = x.Name
});
return View(model);
}
[HttpPost]
public ActionResult createSubCategory(int? id, SubCategoryVM model)
{
SubCategory sc = new SubCategory();
if (ModelState.IsValid)
{
sc.ParentName = model.ParentName;
sc.Name = model.Name;
}
return View();
}
and View:
#model OnlineStore.ViewModels.SubCategoryVM
<div class="form-group">
#Html.LabelFor(model => model.ParentName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.ParentName, Model.categoryNames, "--Please select an option--", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.ParentName, "", new { #class = "text-danger" })
</div>
This code is throwing a null-reference exception on line #Html.DropDownListFor(model => model.ParentName, Model.categoryNames, "--Please select an option--", new { #class = "form-control" }) saying:
Model.categoryName (Object reference not set to an instance of an object).
Please help me debug it.
Thanks in advance.
Problem is when you are posting the form and returning the View with the form data in case of invalid form, categoryNames in the model is becoming null and you have to repopulate the categoryNames before returning the view with model again.
So update your createSubCategory post method as follows:
[HttpPost]
public ActionResult createSubCategory(int? id, SubCategoryVM model)
{
SubCategory sc = new SubCategory();
if (ModelState.IsValid)
{
sc.ParentName = model.ParentName;
sc.Name = model.Name;
}
var cNames = db.Categories.ToList();
model.categoryNames = cNames.Select(x
=> new SelectListItem
{
Value = x.Name,
Text = x.Name
});
return View(model);
}
Related
Following code is to create users. I have a user class, I need to create users here. But I have department id's on a person and that department id refers to another table in the database whose name is Department.
public ActionResult Create()
{
// disable lazy because of error it creates
_db.Configuration.LazyLoadingEnabled = false;
var data = _db.Departments.OrderBy(a => a.DepartmentId).ToList();
ViewData["DepartmentList"] = data;
return View();
}
Here is View:
#{
var departmentLists = ViewData["DepartmentList"]; // Cast the list
}
<div class="form-group">
#Html.LabelFor(model => model.Department, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EnumDropDownListFor(model => model.Department, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Department, "", new { #class = "text-danger" })
</div>
</div>
This model.department part is the where i lost. I need to list my department in order of the list, when user select, i want to select the id of the department.
Like this;
So I want the user to see
Department Name + SubDepartment name
and when they choose from the list, the chosen thing is
departmentid
so I can add in the database like that.
Here is my Create Post method:
public ActionResult Create([Bind(Include = "ID,LastName,FirstMidName,EnrollmentDate,Email,Department,Position,Active")] User user)
{
if (ModelState.IsValid)
{
_db.Users.Add(user);
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
Her is my User class;
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int DepartmentId { get; set; }
// Other fields removed for brevity
}
Here is Department class;
public class Department
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
public string SubDepartmentName { get; set; }
}
Write your Create GET method as follows:
public ActionResult Create()
{
// disable lazy because of error it creates
_db.Configuration.LazyLoadingEnabled = false;
var departmentList = _db.Departments.Select(d => new
{
d.DepartmentId,
DepartmentName = d.DepartmentName + " " + d.SubDepartmentName
}).OrderBy(a => a.DepartmentId).ToList();
ViewBag.DepartmentList = new SelectList(departmentList,"DepartmentId","DepartmentName");
return View();
}
Then in the view:
<div class="form-group">
#Html.LabelFor(model => model.DepartmentId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("DepartmentId", ViewBag.DepartmentList as SelectList, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.DepartmentId, "", new { #class = "text-danger" })
</div>
</div>
Another problem is in your Create POST method. You are not allowing you DepartmentId to pass in your Bind include list. Please update you Create POST method as follows:
public ActionResult Create([Bind(Include = "ID,LastName,FirstMidName,EnrollmentDate,Email,DepartmentId,Position,Active")] User user)
{
if (ModelState.IsValid)
{
_db.Users.Add(user);
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
I have a people controller for user management and I'm trying to figure out how to get the dropdown choice when the user submits from the edit page. Whenever I hit submit on the page, none of the values from the view model seem to carry through to the post. I can't get the value they chose from the drop down to set the role.
See view model below:
public class PersonViewModel
{
public int PersonId { get; set; }
[Display(Name = "Full Name")]
public string FullName { get; set; }
public string Email { get; set; }
[Display(Name = "Current Role")]
public string SetRole { get; set; }
public List<RoleListViewModel> Roles { get; set; }
}
See controller edit functions below:
// GET: People/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Person person = db.people.Find(id);
if (person == null)
{
return HttpNotFound();
}
PersonViewModel pvm = new PersonViewModel();
List<IdentityRole> roles = adb.Roles.ToList();
var rlvm = new List<RoleListViewModel>();
roles.ForEach(x => rlvm.Add(new RoleListViewModel { RoleId = x.Id, RoleName = x.Name }));
pvm.PersonId = person.PersonId;
pvm.FullName = person.FirstName + " " + person.LastName;
pvm.Email = person.Email;
pvm.Roles = rlvm;
ViewBag.RoleList = new SelectList(rlvm, "RoleName", "RoleName", person.CurrentRole);
return View(pvm);
}
// POST: People/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(PersonViewModel pvm)
{
if (ModelState.IsValid)
{
db.Entry(pvm).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
var usr = new AccountController();
var pers = db.people.Where(x => x.PersonId == pvm.PersonId).FirstOrDefault();
usr.UserManager.AddToRoleAsync(pers.NetId, /* their choice should go here but how? */);
db.SaveChanges();
return View(pvm);
}
Here is the cshtml:
<div class="form-group">
#Html.LabelFor(model => model.Roles, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="form-control-static">
#Html.DropDownList("RoleList", null, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Roles, "", new { #class = "text-danger" })
</div>
</div>
Make a variable in your View Model to store the selected value and then in the view use
#Html.DropDownListFor(m => m.SelectedRoleVariable, RolesSelectList, new { #class = "form-control" });
This question already has answers here:
The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'
(6 answers)
Closed 6 years ago.
This is giving me a hard time to implement. I've generated a controller and view to handle updating a model.
However in the Create.cshtml I need to add a drop down with database users (using db.Users.Tolist()) to populate the dropdown.
<div class="form-group">
#Html.LabelFor(model => model.UserId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
// #Html.EditorFor(model => model.UserId, new { htmlAttributes = new { #class = "form-control" } })
#Html.DropDownListFor(model => model.UserId, ViewData["u"] as IEnumerable<SelectListItem>)
</div>
</div>
So I've taken #Html.EditorFor() and replaced it with #Html.DropDownListFor() to show the dropdown list. And this does work but I get an error when I click submit.
The ViewData item that has the key 'UserId' is of type 'System.String' but must be of type 'IEnumerable'.
Here's the Model.
public class pdf
{
[Key]
public int ID { get; set; }
public string UserId { get; set; }
public Guid FileGuid { get; set; }
public string FileName { get; set; }
public string FileLocation { get; set; }
}
And the Create controller.
public ActionResult Create()
{
if (ModelState.IsValid)
{
var u = db.Users.Select(x => new { UserId = x.Id, UserName = x.UserName }).ToList();
//u[0].UserName
ViewBag.userinfo = new System.Web.Mvc.MultiSelectList(u, "UserId", "UserName");
IEnumerable<SelectListItem> u1 = new SelectList(db.Users.ToList(), "Id", "UserName");
ViewData["u"] = u1;
}
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,UserId,FileGuid,FileName,FileLocation")] pdf pdf)
{
if (ModelState.IsValid)
{
db.tblPDF.Add(pdf);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(pdf);
}
I feel that I'm almost there. But just need a push in the right direction to make this work.
This is how you can make your SelectListItems
ViewData["items"] = db.UserProfiles
.Select(x => new SelectListItem() { Text = x.UserName, Value = x.UserId.ToString() });
This is how you would use it
#Html.DropDownListFor(model => model.UserId, ViewData["items"] as IEnumerable<SelectListItem>)
I've never tried passing a selectlistitem collection directly to the page. I typically add the list to the model and then create a new selectlistitem collection with razor.
Do you have the choice to modify your model?
#Html.DropDownListFor(model => model.UserId, Model.availableUsers.Select(user => new SelectListItem() { Text = user.displayVariable, Value = user.userId, Selected = user.userId == model.UserId }).ToArray())
What I'm trying to do...
I am trying to get a newly added item to display in a cascading dropdownlist.
Overview...
The first dropdownlist (I'll call it ddlCategory) is for selecting a Category of electrical devices (ie. Appliances, Audio-Visual, Lighting, etc.). The second dropdownlist (I'll call ddlElecDev) is populated with the devices which are filtered by the selected Category. If the device isn't listed in ddlElecDev then the user can click a link to add a new one. After saving the newly added electrical device, the user is redirected back to the original page with the electrical device id as a parameter.
All the above seems to work fine. However, when the user is redirected to the first page, not only is the newly added electrical device not selected in ddlElecDev, but it doesn't even appear in the list. Strangely, if I refresh the page, it is automatically selected.
Can anyone explain to me how to get the newly added device to be selected without having to refresh the page?
Here's the markup for selecting the category and electrical device:
<div class="form-group">
#Html.LabelFor(model => model.SelectedCategory, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedCategory, Model.Categories, "Select a Category", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.SelectedCategory, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ElectricalDeviceID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.CascadingDropDownListFor(
expression: model => model.ElectricalDeviceID,
triggeredByProperty: model => model.SelectedCategory,
url: Url.Action("GetElectricalDevices", "ElectricalDeviceConfigurations"),
ajaxActionParamName: "categoryId",
optionLabel: "Select an Electrical Device",
disabledWhenParrentNotSelected: false,
htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.ElectricalDeviceID, "", new { #class = "text-danger" })
#Html.ActionLink("Not Listed? Add a new Electrical Device", "AddNew", "ElectricalDevices", new { returnUrl = string.Format("/ElectricalDeviceConfigurations/AddConfiguration?eventVendorId={0}", Model.EventVendorID) }, null)
</div>
</div>
The documentation for the Cascading DropDownList Helper can be found at
https://github.com/alexanderar/Mvc.CascadeDropDown
Here's the Controller method for selecting the Electrical Device:
public ActionResult AddConfiguration(int? eventVendorId, int? newElecDev)
{
(Some code removed for brevity)
var selectedCategoryId = db.ElectricalDeviceCategoryLookups.Where(cat => cat.Category == Enums.ElectricalDeviceCategory.All).FirstOrDefault().ID;
var electricalDeviceID = (newElecDev.HasValue) ? newElecDev : null;
return View(new ElecDevConfigSelectionViewModel { EventVendorID = eventVendorId, EventVendor = eventVendor, Categories = GetCategories(), SelectedCategory = selectedCategoryId, ElectricalDeviceID = electricalDeviceID });
}
Here's the controller methods for populating the Categories and the Electrical Devices:
private List<SelectListItem> GetCategories()
{
var categories = new List<SelectListItem>();
db.ElectricalDeviceCategoryLookups.OrderBy(c => c.Description).ToList().ForEach(item => categories.Add(new SelectListItem { Text = item.Description, Value = item.ID.ToString() } ));
return categories;
}
public ActionResult GetElectricalDevices(int? categoryId)
{
if (categoryId.HasValue)
{
var selCategory = db.ElectricalDeviceCategoryLookups.Where(cat => cat.ID == categoryId).FirstOrDefault().Category;
var elecDevicesSelectList = new List<SelectListItem>();
var elecDevices = (selCategory == Enums.ElectricalDeviceCategory.All) ? db.ElectricalDevices.OrderBy(ed => ed.Name).ToList() : db.ElectricalDevices.Where(ed => ed.Category == selCategory).OrderBy(ed => ed.Name).ToList();
elecDevices.ForEach(ed => elecDevicesSelectList.Add(new SelectListItem { Text = ed.Name, Value = ed.ID.ToString() }));
return Json(elecDevicesSelectList, JsonRequestBehavior.AllowGet);
}
return null;
}
Here's the View Model:
public class ElecDevConfigSelectionViewModel
{
public int? EventVendorID { get; set; }
public EventVendor EventVendor { get; set; }
[Display(Name = "Category")]
public int SelectedCategory { get; set; }
public IList<SelectListItem> Categories { get; set; }
[Display(Name = "Electrical Device")]
public int? ElectricalDeviceID { get; set; }
}
Here's the controller methods for adding a new electrical device:
// GET: ElectricalDevices/AddNew
public ActionResult AddNew(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
var selectedCategoryId = db.ElectricalDeviceCategoryLookups.FirstOrDefault().ID;
return View(new AddNewElectricalDeviceViewModel { ReturnUrl = returnUrl, Categories = GetCategories(), SelectedCategory = null });
}
// POST: ElectricalDevices/AddNew
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddNew(AddNewElectricalDeviceViewModel model)
{
if (ModelState.IsValid)
{
var selectedCategory = db.ElectricalDeviceCategoryLookups.Find(model.SelectedCategory);
var electricalDevice = new ElectricalDevice
{
Name = model.ElectricalDevice.Name,
Description = model.ElectricalDevice.Description,
Category = selectedCategory.Category,
Wattage = model.ElectricalDevice.Wattage
};
db.ElectricalDevices.Add(electricalDevice);
db.SaveChanges();
var returnUrl = string.Format("{0}&newElecDev={1}", model.ReturnUrl, electricalDevice.ID);
return RedirectToLocal(returnUrl);
}
return View();
}
Here's the View Model for adding a new electrical device:
public class AddNewElectricalDeviceViewModel
{
public string ReturnUrl { get; set; }
[Display(Name = "Category")]
public int? SelectedCategory { get; set; }
public IList<SelectListItem> Categories { get; set; }
public ElectricalDevice ElectricalDevice { get; set; }
}
The error occurs when i tried to Submit/Post the data... could someone please help i tried every post but they are not helping me. I am new to mvc... any help will be granted
here is my code...
public ActionResult Create()
{
UserProfileCreateViewModel model = new UserProfileCreateViewModel();
model.Gender = _GenderRepository.GetAll()
.Select(x => new SelectListItem
{
Value = x.ID.ToString(),
Text = x.DESCRIPTION
});
return View(model);
}
[HttpPost]
public ActionResult Create(UserProfileCreateViewModel model)
{
if (ModelState.IsValid)
{
UserProfile user = new UserProfile();
user.GENDER_ID = model.GenderID;
_UserProfileRepository.Add(user);
_UserProfileRepository.Save();
return RedirectToAction("Index", "Home");
}
return View(model);
}
View
<div class="form-group">
#Html.LabelFor(model => model.GenderID, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.GenderID, Model.Gender, "Select from List", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.GenderID, string.Empty, new { #class = "text-danger" })
</div>
</div>
Model
public class UserProfileCreateViewModel
{
[Required(ErrorMessage="{0} is required")]
[Display(Name="Gender")]
public int GenderID { get; set; }
public IEnumerable<SelectListItem> Gender { get; set; }
}
InvalidOperationException: The ViewData item that has the key 'GenderID' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.
Here i have tried this....
// POST: /UserProfile/Create/
[HttpPost]
public ActionResult Create(UserProfileCreateViewModel model)
{
if (ModelState.IsValid)
{
UserProfile user = new UserProfile();
user.GENDER_ID = model.GenderID;
_UserProfileRepository.Add(user);
_UserProfileRepository.Save();
return RedirectToAction("Index", "Home");
}
model.Gender = _GenderRepository.GetAll().Select(x =>
new SelectListItem
{
Value = x.ID.ToString(),
Text = x.DESCRIPTION
});
return View(model);
}
The error means that the value of Model.Gender is null (and as a result the DropDownListFor() method expects that the first parameter is IEnumerable<SelectListItem>.
In your case, when you submit the form and ModelState is invalid, you return the view and have not assigned a value to Model.Gender (hence it is null and the excption is thrown.
Ensure that you re-assign the value of Model.Gender in the POST method (just as you did in the GET method) before you return the view.
It could be a problem between the "Gender":
[Display(Name="Gender")]
public int GenderID { get; set; }
public IEnumerable<SelectListItem> Gender { get; set; }
If I remember well, MVC attempts to map the fields automatically. Try renaming the (Name="Gender") in (Name="GenderID") or IEnumerable<SelectListItem> Gender in IEnumerable<SelectListItem> GenderEnumeration