DropDownListFor Validation Always fires on edit - asp.net-mvc

I have two DropDownListFor elements on a edit view. Even though, value is selected in dropdown, it always fires the DropDownListFor required field validation When i try to submit the view.
public class propertyTypeModel
{
public int type_id { get; set; }
[Required(ErrorMessage = "Property Type Required")]
[Display(Name = "Type")]
public string property_type { get; set; }
}
public class propertyStatusModel
{
public int status_id { get; set; }
[Required(ErrorMessage = "Status Required")]
[Display(Name = "Status")]
public string property_status { get; set; }
}
public class propertyModel
{
public int id { get; set; }
[Display(Name = "Property Type")]
public propertyTypeModel property_type { get; set; }
[Display(Name = "Property Type")]
[Required]
public List<propertyTypeModel> property_type_lst { get; set; }
[Display(Name = "Property Status")]
public propertyStatusModel property_status { get; set; }
[Display(Name = "Property Status")]
[Required]
public List<propertyStatusModel> property_status_lst { get; set; }
}
public ActionResult Edit(int id)
{
rep=new propertyRepository();
propertyModel model = new propertyModel();
model.id = id;
model.property_type_lst = getPropertyTypes();//load dropdown values
model.property_status_lst = getPropertyStatus();//load dropdown values
return View(model);
}
[HttpPost]
public ActionResult Edit(int id, propertyModel model)
{
try
{
model.property_type_lst = getPropertyTypes();
model.property_status_lst = getPropertyStatus();
model.property_owner_lst = getPropertyOwners();
if (ModelState.IsValid)
{
rep = new propertyRepository();
rep.Update(model);
return RedirectToAction("Index");
}
return View(model);
}
catch
{
return View();
}
}
#model RealEstateApp.Models.propertyModel
<div class="editor-label">
#Html.LabelFor(model => model.property_type_lst)
</div>
<div class="editor-field">
#Html.DropDownListFor(x => x.property_type.type_id, new SelectList(Model.property_type_lst, "type_id", "property_type"),"Select Below...")
#Html.ValidationMessageFor(model => model.property_type_lst)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.property_status_lst)
</div>
<div class="editor-field">
#Html.DropDownListFor(x => x.property_status.status_id, new SelectList(Model.property_status_lst, "status_id", "property_status"),"Select Below...")
#Html.ValidationMessageFor(model => model.property_status_lst)
</div>

Try
<div class="editor-field">
#Html.DropDownListFor(model.property_type_lst, new SelectList(Model.property_type_lst, "type_id", "property_type"),"Select Below...", new {id = Model.property_type.type_id})
#Html.ValidationMessageFor(model => model.property_type_lst)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.property_status_lst)
</div>
<div class="editor-field">
#Html.DropDownListFor(model.property_status_lst, new SelectList(Model.property_status_lst, "status_id", "property_status"),"Select Below...", new {id = Model.property_status.status_id})
#Html.ValidationMessageFor(model => model.property_status_lst)
</div>

Related

Asp.net core 6 get value from drop downlist

I am using the #Html.dropdownlistfor that allows the user to choose the customer that creates the deal. But the chhosed customer did not proceed to the controller which led to an unvalid model state. I got the reason that the model was not valid
but I did not know how to solve it. I have followed these links but the problem is still the same.
How do I get the Selected Value of a DropDownList in ASP.NET Core
MVC App
How to get DropDownList SelectedValue in Controller in MVC
SelectList from ViewModel from repository Asp.net core
Sorry if my question is naive I am new to ASP.net core MVC.
the code is as below:
namespace MyShop.ViewModels
{
public class CreateDealVM
{
public Deals deal { get; set; }
public IEnumerable<SelectListItem> CustomerListVM { get; set; }
}
}
The Model class:
namespace MyShop.Models
{
[Table("Deals")]
public class Deals
{
[Key]
[Display(Name = "ID")]
public int dealId { get; set; }
[ForeignKey("Customer")]
[Display(Name = "Customer")]
public Customer customer { get; set; }
[Display(Name = "CustomerName")]
public string? parentCustomerName { get; set; }
[Display(Name = "product")]
public DealTypeEnum product { get; set; }
[Display(Name = "Date")]
public DateTime saleDate { get; set; }
[Display(Name = "Quantity")]
public float quantity { get; set; }
[Display(Name = "Price")]
public float price { get; set; }
}
The Controller:
public IActionResult Create()
{
CreateDealVM vm = new CreateDealVM();
vm.CustomerListVM = _context.Customers.Select(x => new SelectListItem { Value = x.customerId.ToString(), Text = x.customerName }).ToList();
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind("dealId,customer,product,saleDate,quantity,price")] Deals deal, CreateDealVM vm)
{
if (ModelState.IsValid)
{
try
{
vm.deal.customer = _context.Customers.Find(vm.CustomerListVM);
vm.deal = deal;
_context.Deals.Add(vm.deal);
_context.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return View(vm);
}
else
{
var errors = ModelState.Select(x => x.Value.Errors)
.Where(y => y.Count > 0)
.ToList();
//The Error showed here.
}
return View(vm);
}
The view:
#model MyShop.ViewModels.CreateDealVM
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Deals</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
#Html.LabelFor(model => model.deal.customer, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.CustomerListVM,Model.CustomerListVM,"Select Customer", htmlAttributes: new { #class = "form-control"})
</div>
</div>
<div class="form-group">
<label asp-for="deal.product" class="control-label"></label>
<select asp-for="deal.product" class="form-control"></select>
<span asp-validation-for="deal.product" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="deal.saleDate" class="control-label"></label>
<input asp-for="deal.saleDate" class="form-control" />
<span asp-validation-for="deal.saleDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="deal.quantity" class="control-label"></label>
<input asp-for="deal.quantity" class="form-control" />
<span asp-validation-for="deal.quantity" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="deal.price" class="control-label"></label>
<input asp-for="deal.price" class="form-control" />
<span asp-validation-for="deal.price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
I just realise your Model is wrong
[Table("Deals")]
public class Deals
{
[Key]
[Display(Name = "ID")]
public int dealId { get; set; }
[ForeignKey("Customer")]
[Display(Name = "Customer")]
public int CustomerId { get; set; }
[Display(Name = "CustomerName")]
public string? parentCustomerName { get; set; }
[Display(Name = "product")]
public DealTypeEnum product { get; set; }
[Display(Name = "Date")]
public DateTime saleDate { get; set; }
[Display(Name = "Quantity")]
public float quantity { get; set; }
[Display(Name = "Price")]
public float price { get; set; }
public virtual Customer Customer { get; set; }
Change the Dropdown
<div class="col-md-10">
#Html.DropDownListFor(model => model.Deal.CustomerId,Model.CustomerListVM,"Select Customer", htmlAttributes: new { #class = "form-control"})
</div>
one more thing since you have created viewmodel for deal. You only need to do this on your Post Controller
public IActionResult Create()
{
CreateDealVM vm = new CreateDealVM();
vm.CustomerListVM = new SelectList (_context.Customers select new { Id = x.customerId.ToString(), Text = x.customerName }),
"Id","Text");
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Deals deal)
{
CreateDealVM vm = new CreateDealVM();
vm.deal = deal;
vm.CustomerListVM = new SelectList (_context.Customers select new { Id = x.customerId.ToString(), Text = x.customerName }),
"Id","Text",VM.CustomerId);
if (ModelState.IsValid)
{
try
{
_context.Deals.Add(vm.deal);
_context.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return View(vm);
}
else
{
var errors = ModelState.Select(x => x.Value.Errors)
.Where(y => y.Count > 0)
.ToList();
//The Error showed here.
}
return View(vm);
}

Error: There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'Customer'

I need to get all the customers from a different table that is customers into Tickets form.
My Modal....
public class Ticket
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required()]
public Int32 TicketID { get; set; }
public Int32 TicketNum { get; set; }
[Required()]
public DateTime TicketDate { get; set; }
[ForeignKey("Customer")]
public Int32 CustomerID { get; set; }
[Required(ErrorMessage ="Customer Name is required!!")]
[Display(Name ="Customer Name")]
public String CustomerName { get; set; }
public Int32 FieldID { get; set; }
public Int32 WellID { get; set; }
public Int32 WellName { get; set; }
public Int32 LogID { get; set; }
public IEnumerable<SelectListItem> Customers { get; set; }
public virtual Customer Customer { get; set; }
// public virtual Field Field { get; set; }
// public virtual Well Well { get; set; }
// public virtual Log Log { get; set; }
}
My Controller...
[HttpPost]
public ActionResult Create(Ticket ticket)
{
//Very important step
if (!ModelState.IsValid)
{
return View(ticket);
}
Console.WriteLine("Customer: ");
ViewBag.Customers = new SelectList(context.Customers.ToList());
try {
context.Tickets.Add(ticket);
context.SaveChanges();
}
catch(Exception ex)
{
ModelState.AddModelError("Error:" , ex.Message);
return View(ticket);
}
TempData["Message"] = "Created " + ticket.TicketID;
return RedirectToAction("Index");
}
My View.....
<div class="form-group">
#Html.LabelFor(model => model.TicketDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TicketDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.TicketDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CustomerName, "Customer", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Customers", (IEnumerable<SelectListItem>)(ViewBag.Customers), htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CustomerName, "", new { #class = "text-danger" })
</div>
</div>
I know there are number of posts on this and I tried everyone of them.
Firstly you cannot name the ViewBag property the same as the property your binding to, but it appears you want to bind to CustomerID anyway, so your view should be (always use the strongly typed HtmlHelper methods)
#Html.DropDownListFor(m => m.CustomerID, (IEnumerable<SelectListItem>)(ViewBag.Customers), htmlAttributes: new { #class = "form-control" }
Next, the reason you get the exception is because ViewBag.Customers is null. You must reassign the value of the the ViewBag property if you return the view in the POST method. Assuming Customers contains properties CustomerID and CustomerName, then the code in the GET method needs to be
ViewBag.Customers = new SelectList(context.Customers, "CustomerID", "CustomerName");
and in the POST method
if (!ModelState.IsValid)
{
// Reassign the SelectList
ViewBag.Customers = new SelectList(context.Customers, "CustomerID", "CustomerName");
return View(ticket);
}
Console.WriteLine("Customer: ");
// ViewBag.Customers = new SelectList(context.Customers.ToList()); Remove this
try {
....
Finally, based on the view you have shown, you need to remove property public string CustomerName { get; set; } which has a [Required] attribute, meaning ModelState will always be invalid. You have a dropdownlist for selecting the customer which needs to bind to CustomerID and you do not have a control for binding to CustomerName (and nor should you have one)

Unable to populate checkbox from database data in mvc 4

This is my Controller code.
public ActionResult Create()
{
ViewBag.grp_id = new SelectList(db.tm_grp_group, "grp_id", "grp_name");
ViewBag.perm_id = new SelectList(db.tm_perm_level, "perm_id", "perm_levelname");
return View();
}
Below is my view code.
#model Permission.ts_grp_perm_mapping
....
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ts_grp_perm_mapping</legend>
<div class="editor-label">
#Html.LabelFor(model => model.grp_permid)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.grp_permid)
#Html.ValidationMessageFor(model => model.grp_permid)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.grp_id, "tm_grp_group")
</div>
<div class="editor-field">
#Html.DropDownList("grp_id", String.Empty)
#Html.ValidationMessageFor(model => model.grp_id)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.perm_id, "tm_perm_level")
</div>
<div class="editor-field">
#Html.DropDownList("perm_id", String.Empty)
#Html.ValidationMessageFor(model => model.perm_id)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
In controller ViewBag.perm_id contains some values (this is foreign key). In view perm.id displays in the form of dropdownbox but I want it in the form of checkboxlist. How can I achieve this?
This is the viewmodel I created.
public class AssignUserViewModel
{
public tm_perm_level[] perms { get; set; }
public int grp_id { get; set; }
}
Now in controller how can i send values to view? This is my tm_perm_level model
public partial class tm_perm_level
{
public tm_perm_level()
{
this.ts_grp_perm_mapping = new HashSet<ts_grp_perm_mapping>();
}
public int perm_id { get; set; }
public string perm_levelname { get; set; }
public string perm_description { get; set; }
public bool perm_status { get; set; }
public virtual ICollection<ts_grp_perm_mapping> ts_grp_perm_mapping { get; set; }
}
This is ts_grp_perm_mapping model
public partial class ts_grp_perm_mapping
{
public ts_grp_perm_mapping()
{
this.ts_perm_levelmapping = new HashSet<ts_perm_levelmapping>();
}
public int grp_permid { get; set; }
public int grp_id { get; set; }
public int perm_id { get; set; }
public List<tm_perm_level> permissions { get; set; }
public virtual tm_grp_group tm_grp_group { get; set; }
public virtual tm_perm_level tm_perm_level { get; set; }
public virtual ICollection<ts_perm_levelmapping> ts_perm_levelmapping { get; set; }
}
Especially when editing, always start with view models to represent what you want to display (refer What is ViewModel in MVC?)
public class PermissionVM
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class GroupPermissionVM
{
public int GroupID { get; set; }
public IEnumerable<SelectListItem> GroupList { get; set; }
public IEnumerable<PermissionVM> Permissions { get; set; }
}
Then create an EditorTemplate for PermissionVM. In the /Views/Shared/EditorTemplates/PermissionVM.cshtml folder
#model PermissionVM
<div>
#Html.HiddenFor(m => m.ID)
#Html.HiddenFor(m => m.Name)
#Html.CheckBoxFor(m => m.IsSelected)
#Html.LabelFor(m => m.IsSelected, Model.Name)
</div>
and the main view will be
#model GroupPermissionVM
....
#using (Html.BeginForm())
{
// dropdownlist
#Html.LabelFor(m => m.GroupID)
#Html.DropDownListFor(m => m.GroupID, Model.GroupList, "Please select")
#Html.ValidationMessageFor(m => m.GroupID)
// checkboxlist
#Html.EditorFor(m => m.Permissions)
<input type="submit" value="Create" />
}
The controller methods would then be
public ActionResult Create()
{
var groups = db.tm_grp_group;
var permissions = db.tm_perm_level;
GroupPermissionVM model = new GroupPermissionVM
{
GroupList = new SelectList(groups, "grp_id", "grp_name"),
Permissions = permissions.Select(p => new PermissionVM
{
ID = p.perm_id,
Name = p.perm_levelname
}
};
return View(model);
}
[HttpPost]
public ActionResult Create(GroupPermissionVM model)
{
if (!ModelState.IsValid)
{
var groups = db.tm_grp_group;
model.GroupList = new SelectList(groups, "grp_id", "grp_name");
return View(model);
}
// map the view model to a new instance of your data model(s)
// note: to get the ID's of the selected permissions -
// var selectedPermissions = model.Permissions.Where(p => p.IsSelected).Select(p => p.ID);
// save and redirect
}
Side note: I strongly recommend you follow normal naming conventions
Edit
Based on OP's comment for an option using radio buttons to select only one item, the revised code would be
public class PermissionVM
{
public int ID { get; set; }
public string Name { get; set; }
}
public class GroupPermissionVM
{
public int GroupID { get; set; }
public int PermissionID { get; set; }
public IEnumerable<SelectListItem> GroupList { get; set; }
public IEnumerable<PermissionVM> Permissions { get; set; }
}
and the view would be (no separate EditorTemplate required)
#model GroupPermissionVM
....
#using (Html.BeginForm())
{
// dropdownlist as above
// radio buttons
foreach (var permission in Model.Permissions)
{
<label>
#Html.RadioButtonForm(m => m.PermissionID, permission.ID)
<span>#permission.Name</span>
</label>
}
<input type="submit" value="Create" />
}
and in the POST method, the value of model.PermissionID will contain the ID of the selected Permission.

Adding/Update Related Data ASP.NET MVC 5

I'm new to programming so I'm still learning.
I need to add Items to Grocery from a single view. But I can't get the data to save.
When I hit save I don't get any exceptions, the page just loads but nothing is saved to the
database. Can I get some help/guidance as to what I am doing wrong?
Data Class
public class Grocery
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Item> Items { get; set; }
}
public class Item {
public int ItemId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
View Model
public class GroceryViewModel
{
public Grocery Grocery { get; set; }
public virtual Item Item { get; set; }
public GroceryViewModel(int GroceryId)
{
using (var db = new MyContext())
{
Grocery = db.Groceries
.Include("Items")
.SingleOrDefault(a => a.Id == GroceryId);
}
}
}
Controller
public ActionResult Edit(int GroceryId, GroceryViewModel groceryViewModel)
{
var model = new GroceryViewModel(GroceryId);
var plusItems = new Item
{
Name = groceryViewModel.Item.Name,
Description = groceryViewModel.Item.Description,
};
db.Items.Add(plusItems);
db.SaveChanges();
return RedirectToAction(model);
View
#model Project.Models.GroceryViewModel
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Groceries</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Item.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item.Name)
#Html.ValidationMessageFor(model => model.Item.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Item.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<p>
<input type="submit" value="Add Item" />
</p>
</fieldset>
try
using (var db = new MyContext())
{
var grocery = db.Groceries.Single(a => a.Id == groceryId);
var plusItems = new Item
{
Name = groceryViewModel.Item.Name,
Description = groceryViewModel.Item.Description,
};
grocery.Items.Add(plusItems);
db.SaveChanges();
}

Asp.net mvc dropdown list

I am having a bugger of a time trying to figure out where I am going wrong. Scenario is this. Trying to add an object that has a foreign key in it with mvc entity framework.
public class Person
{
[Key]
public virtual int PersonId { get; set; }
[Display(Name = "First Name")]
[Required]
[MaxLength(50)]
public virtual string FirstName { get; set; }
[Display(Name = "Last Name")]
[Required]
[MaxLength(50)]
public virtual string LastName { get; set; }
[Required]
public virtual int TestItem { get; set; }
[Required(ErrorMessage = "Please Select an Employee Type")]
public virtual EmployeeType EmployeeTypeId { get; set; }
}
public class EmployeeType
{
[Key]
public virtual int EmployeeTypeId { get; set; }
[Required]
public virtual string EmployeeTypeName { get; set; }
}
Those are the two pocos for the entities.
public ActionResult Create()
{
PersonViewModel pv = new PersonViewModel();
ViewBag.EmployeeTypeSelect= new SelectList(db.EmployeeTypes, "EmployeeTypeId", "EmployeeTypeName");
return View(pv);
}
//
// POST: /Person/Create
[HttpPost]
public ActionResult Create(PersonViewModel personVM)
{
if (ModelState.IsValid)
{
Person person = new Person();
person.EmployeeTypeId = personVM.EmployeeTypeId;
person.FirstName = personVM.FirstName;
person.LastName = personVM.LastName;
person.TestItem = personVM.TestItem;
db.Persons.Add(person);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(personVM);
}
That is the controller.
#model MvcApplication3.Models.PersonViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>PersonViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TestItem)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TestItem)
#Html.ValidationMessageFor(model => model.TestItem)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.EmployeeTypeId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model=>model.EmployeeTypeId,(SelectList)ViewBag.EmployeeTypeSelect)
#Html.ValidationMessageFor(model => model.EmployeeTypeId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
That is the view.
Everything works fine with the view off the initial get, but when I post the EmployeeTypeId has a null value. I check the source and the select list is fine, has proper values and text. Please help as I have no clue where i am going wrong.
Thanks
Try adding in Html.EndForm() in the HTML after all of the values you wish to post and see if that fixes the problem?
Your Person and EmployeeType class needs to have a default (empty) constructor for the model binding to work -
public class EmployeeType
{
[Key]
public virtual int EmployeeTypeId { get; set; }
[Required]
public virtual string EmployeeTypeName { get; set; }
public EmployeeType()
{
}
}
public class Person {
[Key]
public virtual int PersonId { get; set; }
[Display(Name = "First Name")]
[Required]
[MaxLength(50)]
public virtual string FirstName { get; set; }
[Display(Name = "Last Name")]
[Required]
[MaxLength(50)]
public virtual string LastName { get; set; }
[Required]
public virtual int TestItem { get; set; }
[Required(ErrorMessage = "Please Select an Employee Type")]
public virtual EmployeeType EmployeeTypeId { get; set; }
public Person()
{
EmployeeTypeId = new EmployeeType();
}
}
Also, try in your view, making it
#Html.DropDownListFor(model=>model.EmployeeTypeId.EmployeeTypeId,(SelectList)ViewBag.EmployeeTypeSelect)

Resources