I am registering Cities and for that I want a drop down menu of Countries. The data comes correctly on controller but after that it show errors.
Here is my code 'Model View'
public class CountryCityViewModel
{
public int CountryId { get; set; }
public string name { get; set; }
public SelectList CountryList { get; set; }
public string CountryListId{ get; set; }
}
'CityController'
public async Task<IActionResult> Create()
{
var result = await _countryService.GetAllCountriesCity();
ViewBag.Cities = result;
return View(result);
}
'HTML'
<div class="form-group col-sm-6">
#Html.LabelFor(model => model.CountryId, "Country", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownList(, new SelectList(ViewBag.Cities, "CountryId", "Name"))
#Html.ValidationMessageFor(model => model.CountryId, "", new { #class = "text-danger" })
</div>
'City Service Class'
public async Task<IEnumerable<CountryCityViewModel>> GetAllCountriesCity()
{
var uri = $"{_siteConfiguration.ApiBaseUrl}{ApiEndPoint.Get_Countries_All}";
var response = _httpClient.GetAsync(uri).Result;
var contents = response.Content.ReadAsStringAsync().Result;
var result = JsonConvert.DeserializeObject<IEnumerable<CountryCityViewModel>>(contents);
return await Task.FromResult(result);
}
YourPage.cshtml
#{
var list = _countryService.GetAllCountriesCity().Select(x => new SelectListItem()
{
Value = x.CountryId.ToString(),
Text = x.Name
}).ToList();
}
<select asp-items="#list" asp-for="CountryId" class="form-control"></select>
Related
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);
}
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'm trying to figure out why everything compiles, the page loads, but there's nothing in the Managers drop down menu. The Engineers dropdown populates properly, but not the Managers. I thought that perhaps the query returned no results, but as it should, it returned 2, I displayed the count and verified 2 matches in the table. Why would this not work?
public ActionResult Create()
{
//var userId = User.Identity.GetUserId();
//var user =
ViewBag.StatusId = new SelectList(db.statuses, "StatusId", "StatusName");
ViewBag.SystemDetailId = new SelectList(db.systems, "SystemDetailId", "SystemName");
var engineers = db.engineers;
var managers = db.managers;
var mte = db.ManagersToEngineers;
List<Manager> matchedManager = null;
Engineer matchedEngineer = null;
if (this.User.Identity.IsAuthenticated)
{
var userEmail = this.User.Identity.Name;
matchedEngineer = engineers.Where(x => x.email == userEmail).FirstOrDefault();
if (matchedEngineer != null)
{
matchedManager = mte.Where(x => x.EngineerId == matchedEngineer.PersonId).Select(x => x.manager).ToList();
}
}
if (matchedEngineer != null)
{
ViewBag.EngineerId = new SelectList(new List<Engineer> { matchedEngineer }, "PersonId", "FullName");
ViewBag.ManagerId = new SelectList(matchedManager, "PersonId", "FullName");
}
else
{
ViewBag.EngineerId = new SelectList(engineers, "PersonId", "FullName");
ViewBag.ManagerId = new SelectList(managers, "PersonId", "FullName");
}
return View();
}
Here's the cshtml for create (UPDATE: Engineer drop down shared for reference):
<div class="form-group">
#Html.LabelFor(model => model.EngineerId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("EngineerId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.engineer.FullName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ManagerId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("ManagerId", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.manager.FullName, "", new { #class = "text-danger" })
</div>
</div>
Did you mean to instantiate a new List of Manager in the first line of ViewBag.ManagerId?
if (matchedEngineer != null)
{
ViewBag.EngineerId = new SelectList(new List<Engineer> { matchedEngineer }, "PersonId", "FullName");
// new up list below
ViewBag.ManagerId = new SelectList(new List<Manager>, "PersonId", "FullName");
}
Turns out I was missing the proper ForeignKey annotations in the change model it was being displayed from.
public class ManagerToEngineer
{
[Key]
public int ManagerToEngineerId { get; set; }
[ForeignKey("engineer")]
public int EngineerId { get; set; }
[ForeignKey("manager")]
public int ManagerId { get; set; }
public virtual Engineer engineer { get; set; }
public virtual Manager manager { get; set; }
}
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; }
}
I have two classes where one is a parent class for the other. The basic CRUD functions was created in the controller. In the design of my table I have the parent id in my child class as the foreign key. In the view for Create function of the child, I am asked to enter the parent ID. I have changed the Create to accept the ID of the parent. But when I remove the code for selecting the parent id in the view I get exception in my Create. Is there a way I can set the parent ID in both my create functions(Over loaded functions).
public ActionResult Create(int? id)
{
ViewBag.LsystemID = new SelectList(db.Lsystem, "LsystemID", "LsystemName",id);
ViewBag.TCID = new SelectList(db.TC, "TCID", "TCName");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "OptionID,OptionName,TCID,LsystemID")] Option option)
{
if (ModelState.IsValid)
{
db.Option.Add(option);
db.SaveChanges();
return RedirectToAction("Index");
}
// ViewBag.LsystemID = new SelectList(db.Lsystem, "LsystemID", "LsystemName", op);
ViewBag.TCID = new SelectList(db.TC, "TCID", "TCName", option.TCID);
return View(option);
}
View
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.OptionName, htmlAttributes: new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.OptionName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.OptionName, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.TCID, "TCID", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownList("TCID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.TCID, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.LsystemID, "LsystemID", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownList("LsystemID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.LsystemID, "", new { #class = "text-danger" })
<input type="submit" value="Create" class="btn btn-default" />
}
How can I pass the value LsystemID without being shown in the View?
EDIT 1 : Adding Model class
public class Lsystem
{
public int LsystemID { get; set; }
public string LsystemName { get; set; }
public virtual ICollection<Option> Options { get; set; }
// public int OptionId { get; set; }
}
public class Option
{
public int OptionID { get; set; }
public string OptionName { get; set; }
public int TCID { get; set; }
public virtual TC tc { get; set; }
public virtual Lsystem Lsystem { get; set; }
public int LsystemID { get; set; }
public virtual ICollection<OptionValue> OptionValues { get; set; }
}
Start by creating a view model representing what you need in the view (add validation and display attributes as required
public class OptionVM
{
public int Lsystem { get; set; }
public string Name { get; set; }
public int TC { get; set; }
public SelectList TCList { get; set; }
}
and in the controller
public ActionResult Create(int? id)
{
OptionVM model = new OptionVM
{
Lsystem = id // set the parent
};
ConfigureViewModel(model);
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(OptionVM model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model);
}
Option option = new Option
{
OptionName = model.Name,
TCID = model.TC,
LsystemID= model.Lsystem
};
db.Option.Add(option);
db.SaveChanges();
return RedirectToAction("Index");
}
private void ConfigureViewModel(OptionVM model)
{
model.TCList = new SelectList(db.TC, "TCID", "TCName");
}
and in the view
#model OptionVM
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Lsystem)
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
#Html.ValidationMesageFor(m => m.Name)
#Html.LabelFor(m => m.TC)
#Html.DropDownListFor(m => m.TC, Model.TCList, "Please select")
#Html.ValidationMesageFor(m => m.TC)
<input type="submit" ... />
}