I am using same form for Inserting new records and updating existing records. But, issue is that validation on all controls are shown as soon as form is loaded i.e. it should display validation message summary once this does not match criteria. I want to avoid validation message summary before clicking on submit button.
Controller:
using CRUD_logudTycoon_Revision_3.Context;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace CRUD_logudTycoon_Revision_3.Controllers
{
public class HomeController : Controller
{
// GET: Home
testEntities dbContext = new testEntities();
public ActionResult HomePage()
{
return View();
}
public ActionResult Student(tbl_Student obj)
{
if (obj != null)
{
return View(obj);
}
return View("Student");
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult AddStudent(tbl_Student stu)
{
if (ModelState.IsValid)
{
tbl_Student res = new tbl_Student();
res.ID = stu.ID;
res.Name = stu.Name;
res.Fname = stu.Fname;
res.Email = stu.Email;
res.Mobile = stu.Mobile;
res.Description = stu.Description;
if (stu.ID == 0)
{
dbContext.tbl_Student.Add(res);
dbContext.SaveChanges();
}
else
{
dbContext.Entry(res).State = System.Data.Entity.EntityState.Modified;
dbContext.SaveChanges();
}
}
ModelState.Clear();
//return View("Student");
return RedirectToAction("StudentList");
}
public ActionResult StudentList()
{
var result = dbContext.tbl_Student.ToList();
return View(result);
}
public ActionResult Delete(int ID)
{
var result = dbContext.tbl_Student.Where(x => x.ID == ID).First();
dbContext.tbl_Student.Remove(result);
dbContext.SaveChanges();
var newlist = dbContext.tbl_Student.ToList();
return View("StudentList", newlist);
}
}
}
Student Action (Insert/Edit):
#model CRUD_logudTycoon_Revision_3.Context.tbl_Student
#{
ViewBag.Title = "Student";
}
<style>
.error {
color: red;
}
</style>
<h2>Student Registration Page</h2>
#using (Html.BeginForm("AddStudent", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="container">
<div class="form-group">
#Html.HiddenFor(x => x.ID)
#Html.Label("Student Name")
#Html.ValidationMessageFor(x => x.Name, "", new { #class = "error" })
#Html.TextBoxFor(x => x.Name, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.Label("Father Name")
#Html.ValidationMessageFor(x => x.Fname, "", new { #class = "error" })
#Html.TextBoxFor(x => x.Fname, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.Label("Email")
#Html.ValidationMessageFor(x => x.Email, "", new { #class = "error" })
#Html.TextBoxFor(x => x.Email, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.Label("Mobile")
#Html.ValidationMessageFor(x => x.Mobile, "", new { #class = "error" })
#Html.TextBoxFor(x => x.Mobile, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.Label("Description")
#Html.ValidationMessageFor(x => x.Description, "", new { #class = "error" })
#Html.TextBoxFor(x => x.Description, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.TextBox("btn_Submit", "Submit", new { type = "Submit" })
#Html.TextBox("btn_Reset", "Reset", new { type = "Reset" })
</div>
</div>
}
DB Scripts:
CREATE TABLE [dbo].[tbl_Student]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](150) NULL,
[Fname] [varchar](150) NULL,
[Email] [varchar](150) NULL,
[Mobile] [varchar](150) NULL,
[Description] [varchar](350) NULL,
PRIMARY KEY CLUSTERED ([ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CRUD_logudTycoon_Revision_3.Context
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public partial class tbl_Student
{
public int ID { get; set; }
[Required(ErrorMessage ="Name is requried")]
public string Name { get; set; }
[Required(ErrorMessage = "Father Name is requried")]
public string Fname { get; set; }
[Required(ErrorMessage = "Email is requried")]
[EmailAddress]
public string Email { get; set; }
[Required(ErrorMessage = "Mobile is requried")]
[MinLength(10,ErrorMessage ="10 Digit Mobile No. is required")]
[MaxLength(10, ErrorMessage = "10 Digit Mobile No. is required")]
public string Mobile { get; set; }
[Required(ErrorMessage = "Description is requried")]
public string Description { get; set; }
}
}
I've three dropdownlists each depend on the previous selection (stocks ,category,items) .
each dropdownlist populated by Viewbag from controller
controller:
ViewBag.stock_id = new SelectList(db.stocks, "stock_id", "stock_name");
ViewBag.cat_id = new SelectList(db.categories, "cat_id", "cat_name");
ViewBag.item_id = new SelectList(db.items, "item_id", "item_name");
[HttpGet]
public ActionResult UpdateitemDrop1(int stock_id)
{
var fromDatabaseEF = new SelectList(db.categories.Where(x => x.stock_id == stock_id).ToList(), "cat_id", "cat_name");
SelectList vb = fromDatabaseEF;
return Json(vb, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public ActionResult UpdateitemDrop2(int cat_id)
{
SelectList data= new SelectList(db.items.Where(x => x.cat_id == cat_id).ToList(), "item_id", "item_name");
return Json(data, JsonRequestBehavior.AllowGet);
}
view:
<div class="form-group">
#Html.LabelFor(model => model.stock_id, "stock_id", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("stock_id", null, htmlAttributes: new { #class = "form-control", #id = "stock_id" })
#Html.ValidationMessageFor(model => model.employee_id, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.cat_id, "cat_id", htmlAttributes: new { #class = "control-label col-md-2"})
<div class="col-md-10">
#Html.DropDownList("cat_id", null, htmlAttributes: new { #class = "form-control", #id = "cat_id", disabled = "disabled" })
#Html.ValidationMessageFor(model => model.employee_id, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.item_id, "item_id", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("item_id", null, htmlAttributes: new { #class = "form-control", #id = "item_id" , disabled = "disabled" })
#Html.ValidationMessageFor(model => model.item_id, "", new { #class = "text-danger" })
</div>
</div>
<script>
$(function () {
$('#stock_id').change(function () {
var select = $('#cat_id');
var stockV = $("#stock_id :selected").val();
alert();
$.ajax({
url: '/additions/UpdateitemDrop1',
type: "GET",
dataType: "JSON",
data: { stock_id: stockV },
success: function (vb) {
select.empty();
$(vb).each(function () {
select.add($("<option></option>").val(vb.cat_id).html(vb.cat_name));
});
}
});
});
$('#cat_id').change(function () {
var catV = $("#cat_id :selected").val();
$('#item_id').prop("disabled", false);
alert();
$.ajax({
url: '/additions/UpdateitemDrop2',
type: "GET",
dataType: "JSON",
data: { item_id: catV },
success: function () {
$("#item_id").html("");
$("#item_id").empty();
$.each(data, function (i, items) {
$("#item_id").append(
$('<option></option>').val(items.item_id).html(items.item_name));
});
}
});
});
});
</script>
but when I select option from first dropdownlist (stock_id) ,it stops at "empty()" function and doesn't populate the second dropdownlist
any help please?
This will help.
Controller - I am starting on Index16.
public class Stock
{
public string Id { get; set; } //value
public string Name { get; set; } //text
}
public class Category
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Item
{
public string Id { get; set; }
public string Name { get; set; }
}
public class ViewModel
{
public IList<Stock> StockList { get; set; }
public IList<Category> CategoryList { get; set; }
public IList<Item> ItemList { get; set; }
public string SelectedStock { get; set; }
public string SelectedCategory { get; set; }
public string SelectedItem { get; set; }
}
public class HomeController : Controller
{
[HttpGet]
public ActionResult UpdateitemDrop1(string stock_id)
{
List<Stock> stocks;
List<Category> categories;
List<Item> items;
PopulateViewBags(out stocks, out categories, out items);
var q = categories.Where(x => x.Id == stock_id).ToArray();
return Json(q, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public ActionResult UpdateitemDrop2(string cat_id)
{
List<Stock> stocks;
List<Category> categories;
List<Item> items;
PopulateViewBags(out stocks, out categories, out items);
ViewBag.item_id = new SelectList(items.Where(x => x.Id == cat_id));
return Json(ViewBag.item_id, JsonRequestBehavior.AllowGet);
}
public ActionResult Index16()
{
List<Stock> stocks;
List<Category> categories;
List<Item> items;
PopulateViewBags(out stocks, out categories, out items);
var viewModel = new ViewModel { CategoryList = categories, ItemList = items, StockList = stocks };
return View(viewModel);
}
private void PopulateViewBags(out List<Stock> stocks, out List<Category> categories, out List<Item> items)
{
stocks = new List<Stock> {
new Stock { Id = "1", Name = "Stock1"},
new Stock { Id = "2", Name = "Stock2"},
new Stock { Id = "3", Name = "Stock3"}
};
categories = new List<Category> {
new Category { Id = "1", Name = "Category1"},
new Category { Id = "2", Name = "Category2"},
new Category { Id = "3", Name = "Category3"}
};
items = new List<Item> {
new Item { Id = "1", Name = "Item1"},
new Item { Id = "2", Name = "Item2"},
new Item { Id = "3", Name = "Item3"}
};
ViewBag.cat_id = new SelectList(categories, "Id", "Name");
ViewBag.item_id = new SelectList(items, "Id", "Name");
ViewBag.stock_id = new SelectList(stocks, "Id", "Name");
}
View
#model WebApplication2.Controllers.ViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index16</title>
<script src="~/Scripts/jquery-3.4.1.min.js"></script>
<script>
$(function () {
$('#stock_id').change(function () {
var stockV = $("#stock_id :selected").val();
$.ajax({
url: '/home/UpdateitemDrop1',
type: "GET",
//dataType: "JSON",
data: { stock_id: stockV },
success: function (data) {
alert(data[0].Id);
alert(data[0].Name)
$("#cat_id").html("");
$.each(data, function (i, category) {
$("#cat_id").append(
$('<option></option>').val(category.Id).html(category.Name));
})
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
});
$('#cat_id').change(function () {
alert("category id changed");
//var catV = $("#cat_id :selected").val();
//alert();
//$.ajax({
// url: '/additions/UpdateitemDrop2',
// type: "GET",
// dataType: "JSON",
// data: { item_id: catV },
// success: function () {
// $("#item_id").html("");
// $.each(data, function (i, items) {
// $("#item_id").append(
// $('<option></option>').val(items.item_id).html(items.item_name));
// });
// }
//});
});
});
</script>
</head>
<body>
<div class="form-group">
<div class="col-md-10">
#Html.LabelFor(model => model.StockList[0].Name, "stock_id", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownListFor(model => model.SelectedStock, ViewBag.stock_id as SelectList,
"Select Stock", new { #class = "form-control", #id = "stock_id" })
#Html.ValidationMessageFor(model => model.SelectedStock, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.CategoryList[0].Name, "cat_id", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownListFor(model => model.SelectedCategory, ViewBag.cat_id as SelectList,
"Select Category", new { #class = "form-control", #id = "cat_id" })
#Html.ValidationMessageFor(model => model.SelectedCategory, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.ItemList[0].Name, "item_id", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownListFor(model => model.SelectedItem, ViewBag.item_id as SelectList,
"Select Item", new { #class = "form-control", #id = "item_id" })
#Html.ValidationMessageFor(model => model.SelectedItem, "", new { #class = "text-danger" })
</div>
</div>
</body>
</html>
I am using SelectList to populate dropdownlists in my view. It works for the Create and Edit views to store ID value data in a table. How do I retrieve the 'Name' value to display in a Details view?
Model
Public Class Employee {
[Key]
public int ID { get; set;}
public string UserName {get; set; }
public byte Gender { get; set; }
}
ViewModel
public class EmployeeEditViewModel {
public int ID { get; set; }
public string UserName { get; set; }
public SelectList GenderList { get; set; }
public EmployeeEditViewModel () {
GenderList = CommonHelper.GenderList(null);
}
}
Helper
public static SelectList GenderList(object selected)
{
return new SelectList(new[]
{
new { Value = 0, Name = "Male" },
new { Value = 1, Name = "Female" }
}
, "Value", "Name", selected);
}
Edit View
#model Models.ViewModel.EmployeeEditViewModel
#using (Html.BeginForm()) {
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.UserName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.UserName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.GenderList, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.Gender, Model.GenderList, "- Select -", new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.GenderList, "", new { #class = "text-danger" })
</div>
</div>
}
Controller
[HttpPost]
public ActionResult CreateEmployee(EmployeeEditViewModel emProfile)
{
try
{
if (ModelState.IsValid)
{
Employee newUser = new Employee();
newUser.UserName = emProfile.UserName;
newUser.Gender = emProfile.Gender;
userRepository.Add(newUser);
userRepository.SaveChanges();
return RedirectToAction("Index");
}
}
catch (Exception ex)
{ }
return View(emProfile);
}
So far it works great, I am able to create, edit Employee records and 1 or 0 is stored in the table for the gender.
But when I want to display the employee data in a details view how do I get the text 'Male' or 'Female'?
I ended up creating a helper method to retrieve the text.
public static string GetTextFromSelectList(int id, string listName)
{
string selectedText = string.Empty;
SelectListItem selectedItem;
switch (listName)
{
case "Gender":
selectedItem = Helper.CommonHelper.GenderList(null).FirstOrDefault(x => x.Value == id.ToString());
selectedText = selectedItem == null ? null : selectedItem.Text;
break;
default:
selectedText = null;
break;
}
return selectedText;
}
I created an Enum and the values has id now I need to get the id in #Html.DropDownListFor but I don't know how to do it.
How could I get the id of Enum ?
Enum
public enum GainLosses
{
Gain = 1,
Loss = 2
};
Model
//Gain/Loss
[DisplayName("Gain/Loss")]
public int gainLoss { get; set; }
public IEnumerable<SelectListItem> gainLosses
{
get { return CustomEnum.Enum.GetItems<GainLosses>().Select(x => new SelectListItem() { Text = x.ToString(), Value = x.ToString() }); }
}
//
HTML
<div class="form-group">
<label for="#Html.IdFor(model => model.gainLoss)" class="cols-sm-2 control-label">Gain/Loss <img src="~/Imagens/required.png" height="6" width="6" title="requerido"></label>
#Html.DropDownListFor(model => model.gainLoss, Model.gainLosses, new { Class = "form-control" })
#Html.ValidationMessageFor(model => model.gainLoss, "", new { #class = "text-danger" })
</div><!--/Gain/Loss-->
I've already solved the problem.
[DisplayName("Gain/Loss")]
public int gainLoss { get; set; }
public IEnumerable<SelectListItem> gainLosses
{
get { return CustomEnum.Enum.GetItems<GainLosses>().Select(x => new SelectListItem() { Text = x.ToString(), Value = ((int)x).ToString() }); }
}
//
I have two classes:
public class bill {
public int billId { get;set;}
public decimal billAmount { get;set;}
...................
public virtual ICollection<lift> Lifts { get;set;}
}
public class lift {
public int liftId { get;set;}
public int billId { get;set;}
......
}
I am accessing the child payments related to existing bills by using the following code in my view:
#for (int i = 0; i < Model.Lifts.Where(x => x.archived != true).ToList().Count; i++)
{
<tr>
<td>#Html.EditorFor(model => model.Lifts.ToList()[i].liftId, new { htmlAttributes = new { #class = "form-control" } })</td>
#Html.ValidationMessageFor(model => model.Lifts.ToList()[i].liftId, "", new { #class = "text-danger" })
<td>#Html.EditorFor(model => model.Lifts.ToList()[i].liftDate, new { htmlAttributes = new { #class = "form-control" } })</td>
#Html.ValidationMessageFor(model => model.Lifts.ToList()[i].liftDate, "", new { #class = "text-danger" })
<td>#Html.EditorFor(model => model.Lifts.ToList()[i].liftAmount, new { htmlAttributes = new { #class = "form-control" } })</td>
#Html.ValidationMessageFor(model => model.Lifts.ToList()[i].liftAmount, "", new { #class = "text-danger" })
<td>#Html.EditorFor(model => model.Lifts.ToList()[i].archived, new { htmlAttributes = new { #class = "form-control" } })</td>
#Html.ValidationMessageFor(model => model.Lifts.ToList()[i].archived, "", new { #class = "text-danger" })
<td>#Html.EditorFor(model => model.Lifts.ToList()[i].archivedDate, new { htmlAttributes = new { #class = "form-control" } })</td>
#Html.ValidationMessageFor(model => model.Lifts.ToList()[i].archivedDate, "", new { #class = "text-danger" })
</tr>
}
This is all working as expected including the field validation on the payments if I remove required fields from the lift class but when I post my model to save the changed bill the Model.Lifts entity is always null
How can I bind the changed lift entities from the related bill to the post of my edit controller for bill, I have tried appending the property to the list of other properties but this has not worked. My controller is as follows:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "billId,.......,Lifts")] bill bill)
{
if (ModelState.IsValid)
{
db.Entry(bill).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(bill);
}
Your use of .ToList() within your HtmlHelpermethods is generating name attributes such as name="[0].liftId", name="[0].liftDate" etc, but in order to bind to your model, they need to be name="Lifts[0].liftId", name="Lifts[0].liftDate" (i.e. prefixed with the property name). In adition, you validation will not work correctly.
Since you editing data, you should be using a view model which will also allow you to filter the data in the GET method.
public class LiftVM // add validation and display attributes as required
{
public int ID { get; set; } // no need for a hidden input if you using the default routing
public DateTime Date { get; set; }
.... // note that a billId property will not be required
}
public class BillVM // add validation and display attributes as required
{
public int ID { get; set; }
public decimal Amount { get; set; }
....
public IList<liftVM> Lifts { get; set; }
}
and in the GET method, map your data model to an instance of the view model
bill data = .... // your query to get the data model
BillVM model = new BillVM
{
ID = data.billId,
Amount = data.billAmount,
....
Lifts = data.Lifts.Where(x => !x.archived).Select(x => new LiftVM
{
ID = x.liftId,
Date = x.liftDate,
....
}).ToList()
};
return View(model);
Note, tools such as automapper can make mapping data models to view models easier.
Then in the view
#model BillVM
....
#for (int i = 0; i < Model.Lifts.Count; i++)
{
<tr>
<td>
#Html.EditorFor(m => m.Lifts[i].ID, new { htmlAttributes = new { #class = "form-control" } })
// Note this need to be inside a <td>
#Html.ValidationMessageFor(m => model.Lifts[i].ID, new { #class = "text-danger" })
</td>
and finally, the parameter in your POST method will be BillVM and you map the view model back to the data model if the view model is valid