I want to Check whether the master type already exists or not using remote validation.
In my case the remote validation method is not firing.Can anyone help me?
Model
[Key, Column(Order = 1)]
[StringLength(200)]
[Display(Name = "MasterType")]
[Remote("IsNameAvailable", "MasterSetUps", ErrorMessage = "Master type already exists ")]
public string MasterType { get; set; }
Validation Method
[AllowAnonymous]
public JsonResult IsNameAvailable(string MasterType)
{
bool result = true;
if (s_mode == "ADD")
{
return Json(!db.MasterSetUps.Any(a => a.MasterType == MasterType), JsonRequestBehavior.AllowGet);
}
else if (s_mode == "EDIT" & MasterType != s_Master_Type_name)
{
return Json(!db.MasterSetUps.Any(a => a.MasterType == MasterType), JsonRequestBehavior.AllowGet);
}
return Json(result, JsonRequestBehavior.AllowGet);
}
View
<div class="form-group">
#Html.LabelFor(model => model.MasterType, htmlAttributes: new { #class = "control-label col-sm-2" })
<div class="col-sm-10">
#Html.DropDownList("MasterType", null, htmlAttributes: new { #class = "form-controls" })
#Html.ValidationMessageFor(model => model.MasterType, "", new { #class = "text-danger" })
</div>
</div>
GetMethod
public ActionResult Create()
{
s_mode = "ADD";
ViewBag.MasterType = new SelectList(db.Masters, "MasterType", "MasterType");
return View();
}
Your use of DropDownList(...) means that your not generating the necessary data-val-* attributes for validation. The method is using your ViewBag property for binding (not your model property) and their are no validation attributes associated with ViewBag.
Change the code in the GET method to
ViewBag.MasterTypeList = new SelectList (.....
and the view code to
#Html.DropDownListFor (m => m.MasterType, (SelectList)ViewBag.MasterTypeList, new { ... })
Note that the name of the property your binding to cannot be the same as the SelectList.
Related
I have been trying to find a solution to a situation that I'm busy designing, however I have not managed to get to it.
Imagine having the following model
public enum InputType
{
TextInput,
LookupInput
}
public struct AdditionalProperty
{
public string Key {get;set;}
public string Value {get;set;}
public InputType Type {get;set;}
}
public class Person
{
public string FirstName {get;set;}
public List<AdditionalProperty> AdditionalProperties {get;set;}
}
Then, having the following controller
public class HomeController
{
public ActionResult Index()
{
var model = new Person { FirstName = "MyName" };
model.AdditionalProperties = new List<AdditionalProperty>();
var listItem = new AdditionalProperty
{
Key = "Surname",
Value = "MySurname"
};
model.AdditionalProperties.Add(listItem);
return View(model)
}
}
What I'm looking for is the Razor view code on how to "dynamically" create the properties with the correct input type, bound to something in order for me to be able to still use the model when the form gets posted back to the controller for a Save function.
So the property that is known, would be something like this:
<div class="form-group">
<div class="form-row">
<div class="col-md-6">
#Html.LabelFor(model => model.FirstName, new { #class = "control-label" })
<div>
#Html.TextBoxFor(model => model.FirstName, new { #class = "form-control", placeholder = "Enter Group Name", type = "text" })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
</div>
</div>
</div>
The Idea would then be to have the following. Obviously the below isn't sufficient, and this is where I need the help.
I would like to show the additional properties, one below the other, each on a separate line (using bootstrap row) based on the property.InputType
#foreach (var property in Model.Properties)
{
#Html.LabelFor(model => property.Key, new { #class = "control-label" })
<div>
#if (property.InputType == TextInput)
{
#Html.TextBoxFor(model => property.Value, new { #class = "form-control", placeholder = "Enter Group Name", type = "text" })
}
#Html.ValidationMessageFor(model => property.Key, "", new { #class = "text-danger" })
</div>
}
Thus, I would like to see my view as:
| <label> | <input>
Known Property | FirstName | MyFirstName
Unknown Property | Surname | MySurname
In terms of completeness, I am posting the following answer.
I am going to post the Model, View (Index & EditorTemplates) & Controller to show the complete working solution that I used to test the answer that was given to me.
My Model class for this test
Person.cs
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<AdditionalProperty> AdditionalProperties { get; set; }
}
AdditionalProperty.cs
public struct AdditionalProperty
{
public string Key { get; set; }
public object Value { get; set; }
public DateTime? DateValue
{
get
{
DateTime dateValue;
if (DateTime.TryParse(Value?.ToString(), out dateValue))
{
return dateValue;
}
return null;
}
set => Value = value;
}
public InputType InputType { get; set; }
public List<SelectListItem> ValueLookupItems { get; set; }
}
The reason I have a separate DateValue property here is to assist the browser when doing DateTime binding otherwise the DateTimePicker doesn't show.
I used an enum to determine what type of input type this specific property should make use of.
InputType.cs
public enum InputType
{
TextBox,
DropdownBox,
TextArea,
DateSelection,
}
In order to keep the views as simple as possible, Stephen provided me with a sample for the Index View as well as an EditorTemplate for the AdditionalProperty object. The EditorTemplate is used for separation of concerns and to ensure that all the logic behind what input type is being used is in one place.
I have found that the DateTime property doesn't work well, so an additional EditorTemplate was required. I got this from this post.
DateTime.cshtml
Note: Location of template -> /Views/Shared/EditorTemplates
#model DateTime
#{
IDictionary<string, object> htmlAttributes;
object objAttributes;
if (ViewData.TryGetValue("htmlAttributes", out objAttributes))
{
htmlAttributes = objAttributes as IDictionary<string, object> ?? HtmlHelper.AnonymousObjectToHtmlAttributes(objAttributes);
}
else
{
htmlAttributes = new RouteValueDictionary();
}
htmlAttributes.Add("type", "date");
String format = (Request.UserAgent != null && Request.UserAgent.Contains("Chrome")) ? "{0:yyyy-MM-dd}" : "{0:d}";
#Html.TextBox("", Model, format, htmlAttributes)
}
AdditionalProperty.cshtml
Note: Location of template -> /Views/Shared/EditorTemplates
Note: The location of my AdditionalProperty formed part of the DynamicViewExample.Models namespace
#model DynamicViewExample.Models.AdditionalProperty
<div>
#Html.HiddenFor(m => m.Key)
#Html.LabelFor(m => m.Key, Model.Key, new {#class = "control-label"})
#if (Model.InputType == DynamicViewExample.Models.InputType.TextBox)
{
#Html.TextBoxFor(m => m.Value, new {#class = "form-control"})
}
else if (Model.InputType == DynamicViewExample.Models.InputType.TextArea)
{
#Html.TextAreaFor(m => m.Value, new {#class = "form-control"})
}
else if (Model.InputType == DynamicViewExample.Models.InputType.DropdownBox)
{
#Html.DropDownListFor(m => m.Value, Model.ValueLookupItems, new {#class = "form-control"})
}
else if (Model.InputType == DynamicViewExample.Models.InputType.DateSelection)
{
#Html.EditorFor(m => m.DateValue, new {#class = "form-control"})
}
else
{
#Html.HiddenFor(m => m.Value) // we need this just in case
}
</div
This would be how the Index.cshtml file would look
#model DynamicViewExample.Models.Person
#{
ViewBag.Title = "Home Page";
}
#using (Html.BeginForm())
{
<div class="row">
#Html.LabelFor(model => model.FirstName, new { #class = "control-label" })
#Html.TextBoxFor(model => model.FirstName, new { #class = "form-control", placeholder = "Enter Group Name", type = "text" })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
<div class="row">
#Html.LabelFor(model => model.LastName, new { #class = "control-label" })
#Html.TextBoxFor(model => model.LastName, new { #class = "form-control", placeholder = "Enter Group Name", type = "text" })
#Html.ValidationMessageFor(model => model.LastName, "", new { #class = "text-danger" })
</div>
<div class="row">
#Html.EditorFor(m => m.AdditionalProperties, new { htmlAttributes = new { #class = "form-control"}})
</div>
<input type="submit" class="btn btn-primary" />
}
And then finally, the HomeController.cs file contains a Get and Post that allows the ability to manipulate the data as you please. What is missing here is the "dynamic" way of populating the model, but that will naturally happen once a DB has been introduced into the mix.
[HttpGet]
public ActionResult Index()
{
var model = new Person
{
FirstName = "Gawie",
LastName = "Schneider",
AdditionalProperties = new List<AdditionalProperty>
{
new AdditionalProperty {Key = "Identification Number", Value = "1234567890123456", InputType = InputType.TextBox},
new AdditionalProperty {Key = "Date Of Birth", Value = DateTime.Today, InputType = InputType.DateSelection},
new AdditionalProperty {Key = "Age", Value = "31", InputType = InputType.TextBox},
new AdditionalProperty {Key = "Gender", Value = "Male", InputType = InputType.DropdownBox,
ValueLookupItems = new List<SelectListItem>
{
new SelectListItem{Text = "Male", Value = "Male"},
new SelectListItem{Text = "Female", Value = "Female"}
}},
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(Person model)
{
//Do some stuff here with the model like writing it to a DB perhaps
return RedirectToAction("Index");
}
So if I would have to sum up what I was trying to do here.
The goal I wanted to achieve was to be able to make use of Strongly Typed / Known Properties in conjunction with Dynamic / Unknown Properties to create a system that would allow the user to create new inputs on the fly without the need for a developer to be involved.
I honestly hope that this might help someone else as well some day.
Enjoy the coding experience
Gawie
I can get all Roles plus actually Role for chosed user, but then When I posting to EditUser action, then Dropdownlist sends null.
I mean When the form posts to my controller, I get null from DropDownList.
Here is my Model
public class EditUserViewModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public List<SelectListItem> ApplicationRoles { get; set; }
public string ApplicationRoleId { get; set; }
}
Here is Action
[HttpGet]
public async Task<ActionResult> EditUser(string id)
{
EditUserViewModel model = new EditUserViewModel();
model.ApplicationRoles = RoleManager.Roles.Select(r => new SelectListItem
{
Text = r.Name,
Value = r.Id
}).ToList();
if (!String.IsNullOrEmpty(id))
{
ApplicationUser user = await UserManager.FindByIdAsync(id);
if (user != null)
{
var role = await UserManager.GetRolesAsync(user.Id);
var existingRole = role.First();
string existingRoleId = RoleManager.Roles.Single(r => r.Name == existingRole).Id;
model.Id = user.Id;
model.FirstName = user.FirstName;
model.ApplicationRoleId = existingRoleId;
ViewBag.RoleId = new SelectList(RoleManager.Roles, "Id", "Name", model.ApplicationRoleId);
}
}
return PartialView("_EditUser", model);
}
And here is DropDownlist from _EditUser.cshtml
<div class="form-group">
#Html.Label("Role typ", htmlAttributes: new { #class = "control-label col-md-6" })
<div class="col-md-12" title="Ange antal datorer som finns i lager">
#Html.DropDownList("RoleId", null, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.ApplicationRoles, "", new { #class = "text-danger" })
</div>
</div>
Getting null Only from DropDownList, not from #Html.EditorFor
/Thanks in advance!
Forms post back the name/value pairs of their successful form controls. Your generating a <select> element with name="RoleId" but you model does not contain a property named RoleId. Since you want to bind the selected option to the ApplicationRoleId role property, then you view needs to be
#Html.LabelFor(m => m.ApplicationRoleId)
#Html.DropDownListFor(m => m.ApplicationRoleId, Model.ApplicationRoles)
#Html.ValidationMessageFor(m => m.ApplicationRoleId)
Notes:
Your current #Html.Label(..) code does not create a label
associated with your dropdownlist (clicking on it will not set
focus)
The ValidationMessageFor() need to be applied to the property your
binding to, not the SelectList
Delete you ViewBag.RoleId = new SelectList(..) code. Your have
already assigned the selectlist to the ApplicationRoles property
(and you should never need ViewBag if have a view model anyway)
Because you are declare that only HttpGet methods are allow in that method of the controller. Thats why
I am using boilerplate CRUD methods, which include BIND operations on the methods that catch the form submissions. I have discovered that if I have my fields as nullable both in the model as well as in the DB, and I do not include those fields in a CRUD operation (also no presence in BIND), these fields end up null when before they were filled. If I flag these fields as not nullable in the DB, I cannot complete the CRUD operation without including these fields in hidden form fields because they are not nullable.
How do I make a CRUD operation ignore these fields without adding them as hidden fields in the forms?? As in, do not null them, do not change their data.
For example, if I have my POST method as such:
public async Task<ActionResult> Edit([Bind(Include = "CompanyId,CompanyName,CompanyAddress,CompanyCity")] Company company) {
And there is a field both in the model as well as in the DB such as CompanyCity, if it is nullable in model and db it gets nulled with the update. If it is not nullable in the model and db, the update fails because the field is not nullable but the update wants to null it because it didn't exist in the bind.
I am also using only the base models, such as Company, for this example. However when I try to make another base model, such as EditCompanyViewModel, I am unable to pull data out of the database to put into that view model. The entire await command gets flagged as being not of the correct model/type.
Essentially, I need to know how to edit only part of a table, without messing/mucking/deleting the rest of the table entries and without creating a metric arseload of hidden form fields that exist purely to hold the data I don't want to edit.
I have a conceptual gap here, and I am metaphorically chasing my tail. I can't seem to bridge the gap to a solution.
EDIT:
My modified view model:
public class EditMarketingViewModel {
[Key]
public Guid CompanyId { get; set; }
[DisplayName("How did you hear of us")]
public Guid? HowHeardId { get; set; }
[DisplayName("eNewsletter")]
public bool eNewsletter { get; set; }
[DisplayName("Event Code")]
public Guid? EventCodeId { get; set; }
[DisplayName("Notes")]
public string MarketingNotes { get; set; }
#region Essentials
[HiddenInput, Timestamp, ConcurrencyCheck]
public byte[] RowVersion { get; set; }
[HiddenInput]
public DateTime Modified { get; set; }
[HiddenInput]
public string TouchedBy { get; set; }
#endregion
}
My view:
#model CCS.Models.EditMarketingViewModel
#{
ViewBag.Title = "Edit Marketing Info.";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>#ViewBag.Title</h2>
#using(Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<fieldset>
#Html.HiddenFor(model => model.CompanyId)
#Html.HiddenFor(model => model.RowVersion)
#Html.LabelFor(model => model.HowHeardId, htmlAttributes: new { #class = "control-label" })#Html.DropDownList("HowHeardId", null, " « ‹ Select a How Heard Type › » ", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.HowHeardId, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.eNewsletter, htmlAttributes: new { #class = "control-label" })#Html.EditorFor(model => model.eNewsletter, new { htmlAttributes = new { #data_on_text = "Yes", #data_off_text = "No" } })
#Html.ValidationMessageFor(model => model.eNewsletter, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.EventCodeId, htmlAttributes: new { #class = "control-label" })#Html.DropDownList("EventCodeId", null, " « ‹ Select an Event Code › » ", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.EventCodeId, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.MarketingNotes, htmlAttributes: new { #class = "control-label" })#Html.EditorFor(model => model.MarketingNotes, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.MarketingNotes, "", new { #class = "text-danger" })
<input type="submit" value="Save" class="btn btn-default" />
</fieldset>
}
<p>[ #Html.ActionLink("Back to List", "Index", "Company") ]</p>
Now how do I modify my controller to work with it:
// GET: Company/EditMarketing
public async Task<ActionResult> EditMarketing() {
var id = new Guid(User.GetClaimValue("CWD-Company"));
Company company = await db.Company.FindAsync(id);
if(company == null) {
return HttpNotFound();
}
ViewBag.HowHeardId = new SelectList(db.HowHeard.Where(x => x.Active == true).OrderBy(x => x.SortOrder), "HowHeardId", "HowHeardType", company.HowHeardId);
ViewBag.EventCodeId = new SelectList(db.EventCode.Where(x => x.Active == true).OrderBy(x => x.EventCodeDate), "EventCodeId", "EventCodeName", company.EventCodeId);
return View(company);
}
EDIT 2:
My POST:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EditMarketing([Bind(Include = "CompanyId,HowHeardId,eNewsletter,EventCodeId,MarketingNotes,RowVersion")] Company company) {
try {
if(ModelState.IsValid) {
TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
company.Modified = DateTime.UtcNow;
company.TouchedBy = User.Identity.GetFullNameLF();
db.Entry(company).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index", "Company");
}
} catch(DbUpdateConcurrencyException ex) {
var entry = ex.Entries.Single();
var companyValues = (Company)entry.Entity;
var databaseValues = (Company)entry.GetDatabaseValues().ToObject();
if(databaseValues.MarketingNotes != companyValues.MarketingNotes) { ModelState.AddModelError("MarketingNotes", "Current Value: " + databaseValues.MarketingNotes); }
if(databaseValues.eNewsletter != companyValues.eNewsletter) { ModelState.AddModelError("eNewsletter", "Current Value: " + databaseValues.eNewsletter); }
if(databaseValues.HowHeardId != companyValues.HowHeardId) { ModelState.AddModelError("HowHeardId", "Current Value: " + db.HowHeard.Find(databaseValues.HowHeardId).HowHeardType); }
if(databaseValues.EventCodeId != companyValues.EventCodeId) { ModelState.AddModelError("EventCodeId", "Current Value: " + db.EventCode.Find(databaseValues.EventCodeId).EventCodeName); }
ModelState.AddModelError(string.Empty, "The record you attempted to edit "
+ "was modified by another user after you got the original value. The "
+ "edit operation was canceled and the current values in the database "
+ "have been displayed. If you still want to edit this record, click "
+ "the Save button again. Otherwise click the Back to List hyperlink.");
company.RowVersion = databaseValues.RowVersion;
} catch(DataException dex) {
ModelState.AddModelError(string.Empty, "Unable to save changes. Try again, and if the problem persists please inform your Manager, who will inform the developers." + dex);
}
ViewBag.HowHeardId = new SelectList(db.HowHeard.Where(x => x.Active == true).OrderBy(x => x.SortOrder), "HowHeardId", "HowHeardType", company.HowHeardId);
ViewBag.EventCodeId = new SelectList(db.EventCode.Where(x => x.Active == true).OrderBy(x => x.EventCodeDate), "EventCodeId", "EventCodeName", company.EventCodeId);
return View(company);
}
Please note that I am making use of concurrency to avoid data collisions. Hence the RowVersion column.
As I understand your code EditMarketingViewModel is used to update a company record. Pass your view model as parameter to your post action result. You would want to load the company record first before updating it like so. This approach makes your record retain property values which are not needed to be updated.
[HttpPost]
public async Task<ActionResult> Edit(EditMarketingViewModel viewModel)
{
if (!ModelState.IsValid)
{
ViewBag.HowHeardId = new SelectList(db.HowHeard.Where(x => x.Active == true).OrderBy(x => x.SortOrder), "HowHeardId", "HowHeardType", company.HowHeardId);
ViewBag.EventCodeId = new SelectList(db.EventCode.Where(x => x.Active == true).OrderBy(x => x.EventCodeDate), "EventCodeId", "EventCodeName", company.EventCodeId);
return View(viewModel);
}
Company company = await db.Company.FindAsync(viewModel.CompanyId);
if(company == null) {
return HttpNotFound();
}
company.HowHeardId = viewModel.HowHeardId;
company.eNewsletter = viewModel.eNewsletter;
// etc.
// don't need to assign a new value to properties that should be retained
db.Entry(company).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
Update:
You are returning an object of type Company from your GET controller but your view is expecting an EditMarketingViewModel. So do it like this:
// GET: Company/EditMarketing
public async Task<ActionResult> EditMarketing() {
var id = new Guid(User.GetClaimValue("CWD-Company"));
Company company = await db.Company.FindAsync(id);
if(company == null) {
return HttpNotFound();
}
ViewBag.HowHeardId = new SelectList(db.HowHeard.Where(x => x.Active == true).OrderBy(x => x.SortOrder), "HowHeardId", "HowHeardType", company.HowHeardId);
ViewBag.EventCodeId = new SelectList(db.EventCode.Where(x => x.Active == true).OrderBy(x => x.EventCodeDate), "EventCodeId", "EventCodeName", company.EventCodeId);
EditMarketingViewModel viewModel = new EditMarketingViewModel()
{
CompanyId = company.Id,
// Other view model properties go here
}
return View(viewModel);
}
Make sure the object type you are returning from the controller to the view matches.
I am currently new to Asp.net MVC .In one of the view I add a dropdownlist and I bind this dropdownlist with my database like this
Controller CollegeController
[HttpGet]
public ActionResult Create()
{
IEnumerable<SelectListItem> items = db.College_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Name });
IEnumerable<SelectListItem> item = db.Stream_Names.Select(c => new SelectListItem { Value = c.id.ToString(), Text = c.Stream });
ViewBag.CollName=items;
ViewBag.StreamName = item;
return View();
}
[HttpPost]
public ActionResult Create(College college)
{
try
{
if(ModelState.IsValid)
{
db.Colleges.Add(college);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CollName = db.Colleges;
return View(college);
}
catch
{
return View();
}
}
This is my model
public class College
{
[Required]
public int Id { get; set; }
[Required]
[Display(Name="College Name")]
public int CollegeName { get; set; }
[Required]
public int Stream { get; set; }
[Required]
[Column(TypeName="varchar")]
public string Name { get; set; }
....
public virtual College_Name College_Name { get; set; }
public virtual Stream_Name Stream_Name { get; set; }
}
This is My View
<div class="form-group">
#Html.LabelFor(model => model.CollegeName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CollName", (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CollegeName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Stream, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("StreamName", (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Stream, "", new { #class = "text-danger" })
</div>
</div>
Now when I check my database after I save the CollegeName and Stream in the database is zero from the dropdownlist.
You have multiple problems with your code. Firstly you dropdownlists are binding to a properties named CollName and StreamName which do not even exist in your model.
Next you cannot name the property your binding to the same as the ViewBag property.
Your view code would need to be (and always use the strongly typed xxxFor() HtmHelper methods
#Html.DropDownListFor(m => m.CollegeName, (IEnumerable<SelectListItem>)ViewBag.CollName, "Select College", new { #class = "form-control" })
....
#Html.DropDownListFor(m => m.Stream, (IEnumerable<SelectListItem>)ViewBag.StreamName, "Select Stream", new { #class = "form-control" }
and in your POST method, the values of college.CollegeName and college.Stream will contain the ID's of the selected options.
You also need to repopulate the ViewBag properties when you return the view in the POST method (as you did in the GET method) or an exception will be thrown (and note that your current use of ViewBag.CollName = db.Colleges; will also throw an exception)
I also strongly suggest you start learning to use view models (views for editing should not use data models - refer What is ViewModel in MVC?) - and use naming conventions that reflect what your properties are, for example CollegeNameList, or CollegeNames, not CollName
Using a ViewModel for validation:
public class CCvm
{
[Required(ErrorMessage = "Please enter your Name")]
public string cardHolderName { get; set; }
}
My controller calls a task on post:
public async Task<ActionResult> Pay(FormCollection form, CCvm model)
{
if (!ModelState.IsValid)
{
return View(model);
}
}
And the View:
#model GCwholesale.Models.CCvm
#{
Layout = "~/Views/Shared/_HomeSubPageLayout.cshtml";
ViewBag.Title = "Secure Checkout";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="Payment">
<label>Name on Card: </label>
#Html.EditorFor(model => model.cardHolderName, new { htmlAttributes = new { #placeholder = "Cardholder Name Please", #Value = ViewBag.Name } })<br />
#Html.ValidationMessageFor(model => model.cardHolderName)
<button class="submitCheckout">SUBMIT NOW</button>
</div>
}
But when validation fails the data in the form goes away.
Thanks for taking a look.
You do not need to set #Value = ViewBag.Name inside EditorFor.
#Html.EditorFor(model => model.cardHolderName,
new { htmlAttributes = new { #placeholder = "Cardholder Name Please" } })
Besides, you do not need FormCollection as a parameter because you already have CCvm Model.
public async Task<ActionResult> Pay(CCvm model){
{
//...
}
#Value = ViewBag.Name
You're not setting the ViewBag.Name, so it wouldn't have a value and would result in a blank input. Remove that and let the HtmlHelper set it based off the value in the posted model.