Driving me crazy.... validation not firing.
When I leave the field blank and hit submit it behaves as if the model were valid.
I have used dbFirst entity framework to create the model and added the required data annotation after the fact.
My Model (Entity)
public partial class Certificate
{
public Certificate()
{
this.Travelers = new HashSet<Traveler>();
}
public int ID { get; set; }
public System.DateTime InsertDate { get; set; }
[Required(ErrorMessage = "Please enter your card number.")]
public string CertificateNumber { get; set; }
public Nullable<int> BuyerID { get; set; }
public string Used { get; set; }
public string Active { get; set; }
public virtual ICollection<Traveler> Travelers { get; set; }
}
My Controller:
[HttpPost]
public ActionResult Index(Certificate CertificateNumber)
{
if (ModelState.IsValid)
{
return RedirectToAction("Create", "Travelers");
}
return View();
}
My View:
#model GrandCelebration.Models.Certificate
#{
ViewBag.Title = "Validation";
}
<div>
<h2>Please enter your card number below to validate</h2>
<div id="searchbar">
#using (Html.BeginForm())
{#Html.ValidationSummary(true)
<fieldset>
#Html.TextBoxFor(model => model.CertificateNumber)
<input type="submit" class="btn" alt="Validate" style="display:inline" value="Validate" />
#Html.ValidationMessageFor(model => model.CertificateNumber)
</fieldset>
}
</div>
</div>
The problem was that the required js files weren't included.
Firstly make sure that unobtrusive validation is enabled in Web.config:
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
Then include 3 js files in the _Layout page:
<script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.4.2.min.js"></script>
<script src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
When cient-side validation is successfully enabled, if you look at the textbox HTML you will see a data-val property has been added.
Related
I've got a controller to retrieve and return values for my drop down, and a second, that when an option from the dropdown is selected, uses the values (Title and ID) in an API Request.
Controllers
public ActionResult GetEpics()
{
//Code to retrieve list
Epics = new GetEpicsViewModel();
Epics.Epics = epicsList;
return View(Epics);
}
[HttpPost]
public ActionResult Build(GetEpicsViewModel epic)
{
GetEpicsViewModel epicTest = epic;
//API Request
return View();
}
This is displayed in my drop down list as below:
View
#using (Html.BeginForm("Build", "GetEpics", FormMethod.Post))
{
<label for="input_OutputType"> Process: #Html.DropDownListFor(model => model.Id, new SelectList(Model.Epics, "Id", "Title")) </label>
<input type="submit" value="Submit" />
}
This works fine, but how would I then go about passing both the Title and ID to my controller?
I can pass the ID through fine, but cant figure out how to pass the Title as well.
Screenshot
Models
public class DevOpsEpic
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
and
public class GetEpicsViewModel
{
public string Id { get; set; }
public string Title { get; set; }
public List<DevOpsEpic> Epics { get; set; }
}
Realise this is probably a really simple answer, but just cant figure it out!
You can use jQuery for that, so when your dropdown is changed, set title value in hidden file.
#using (Html.BeginForm("Build", "GetEpics", FormMethod.Post))
{
<label for="input_OutputType"> Process: #Html.DropDownListFor(model => model.Id, new SelectList(Model.Epics, "Id", "Title"),new { name = "Id" }) </label>
<input type="hidden" id="Title" name="Title" />
<input type="submit" value="Submit" />
}
$('#dropdownId').change(function(){
$('#Title').val($('#dropdownId option:selected').text());
});
I am using autogenerated entity model classes and than i used partial class with metadata to put validations on auto genetrated classes like below.
public class tblDepartmentCustom
{
[Key]
public int DepartmentId { get; set; }
[Required(ErrorMessage = "Department name is required")]
public string DepartmentName { get; set; }
}
[MetadataType(typeof(tblDepartmentCustom))]
public partial class tblDepartmentMaster
{
}
The original class that was generated by entity framework is given below.
public partial class tblDepartmentMaster
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public tblDepartmentMaster()
{
this.tblDesignationMasters = new HashSet<tblDesignationMaster>();
}
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<tblDesignationMaster> tblDesignationMasters { get; set; }
}
So the problem here is that whenever i try to validated model state it comes out to be true.below is the code.
#model EmployeeManager.Models.tblDepartmentCustom
#{
ViewBag.Title = "InsertDepartment";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}<div class="col-md-4">
#using (Html.BeginForm("InsertDepartment", "Departments", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<span class="error-class">#ViewBag.FoundError</span>
<br />
<label>Department Name</label>
#Html.TextBoxFor(m => m.DepartmentName, new { #class = "form-control" })
<br />
<input type="submit" class="btn btn-info" value="Add Department" />
}
</div>
And the action below.
[HttpGet]
public ActionResult InsertDepartment()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
[ActionName("InsertDepartment")]
public ActionResult InsertDepartmentPost()
{
using (PMSEntities dc = new PMSEntities())
{
tblDepartmentMaster dm = new tblDepartmentMaster();
TryUpdateModel(dm);
if(ModelState.IsValid)
{
dc.tblDepartmentMasters.Add(dm);
dc.SaveChanges();
return View("_Success");
}
else
{
ViewBag.FoundError = "Department name is required.";
return View();
}
}
}
In order for partial classes to work, both partials must have the same namespace. You don't have to move the actual files around your file structure, just edit the namespace of tblDepartmentCustom to match that of tblDepartmentMaster.
I have a view with the name "Create". This view gets the "SchoolViewModel" which contains two classes:
public class SchoolViewModel
{
public List<Teacher> ListTeacher { get; set; }
public List<SchoolClass> ListSchoolClass { get; set; }
public ClassComplete ClassComplete { get; set; }
}
Each list in "SchoolViewModel" provides data from a database.
At the "Create" page you should be able now to select a teacher and class (DropDownList). The "ClassComplete" object contains the two classes (Teacher and SchoolClass) and the roomname
public class ClassComplete
{
public string RoomName { get; set; }
public SchoolClass SchoolClass { get; set; }
public Teacher Teacher { get; set; }
}
I want only to post the "ClassComplete" object.
My ActionResult
[HttpPost]
public ActionResult Create(ClassComplete cp)
{
// Do something
return View();
}
Edit:
Razor View
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.ListTeacher[0].TeacherName)
#Html.EditorFor(m => m.ListSchoolClass[0].ClassName)
#Html.TextBoxFor(m => m.cl.RoomName)<br />
<input type="submit" value="Click" />
}
Is this the right way ?
best regards
If you want to POST only ClassComplete model you will need to indicate the binding prefix:
[HttpPost]
public ActionResult Create([Bind(Prefix="ClassComplete")] ClassComplete cp)
{
// Do something
return View();
}
and in your view:
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.ClassComplete.RoomName)
<br />
<input type="submit" value="Click" />
}
The TextBoxFor will generate the following input field in the resulting markup:
<input type="text" name="ClassComplete.RoomName" />
Notice the name of the input field. That's the reason why you need to indicate this prefix in your controller action.
This will also work for the other properties if you want to send them you just need to include the corresponding input fields:
#Html.TextBoxFor(m => m.ClassComplete.SchoolClass.SomeProperty)
#Html.TextBoxFor(m => m.ClassComplete.Teacher.SomeOtherProperty)
...
I have a drop down list in MVC
Model:
[Required]
[Display(Name = "State of Residency:")]
public string StateCode { get; set; }
My View:
#Html.DropDownList("StateCode", "Select")
#Html.ValidationMessageFor(model => model.StateCode)
The drop down list works fine but how to make the validator validate the select. So it say please select a value in Select is there.
Example for ASP.NET MVC 5 web application:
In your case I would make like so:
1) Enable validation in web.config
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
2) add proper jQuery files
<script src="~/Scripts/jquery-1.11.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script> <!--v1.13.0-->
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> <!-- For ASP.NET MVC 5.0 -->
3) StateCode.cs
public class StateCode
{
public int Id { get; set; }
public int Code { get; set; }
}
4) MyModel.cs
public class MyModel
{
[Required(ErrorMessage = "Please select")]
public int IdSelected { get; set; }
[Display(Name = "State of Residency:")]
public IEnumerable<StateCode> StateCodes { get; set; }
}
5) Action
[HttpGet]
public virtual ActionResult Index()
{
var model = new MyModel
{
StateCodes = new List<StateCode>
{
new StateCode{Id=1, Code=22333},
new StateCode{Id=2, Code=44433},
new StateCode{Id=3, Code=55533},
}
};
return View(model);
}
6) View
#model MyModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(model => model.IdSelected, new SelectList(Model.StateCodes, "Id", "Code"), "Please Select")
#Html.ValidationMessageFor(model => model.IdSelected)
<input type="submit" value="OK" />
}
btw. here very good list of jQuery files for ASP.NET MVC unobtrusive validation.
Having the following classes:
public class MyObjB {
[Required(ErrorMessage = "I need it")]
public string Name { get; set; }
}
public class MyObjA {
[Required(ErrorMessage = "I need it")]
public string Name { get; set; }
public MyObjB MyObjB { get; set; }
}
The View: using the model as MyObjA
#{ Html.EnableClientValidation(); }
#{Html.BeginForm();}
#Html.ValidationSummary("Some errors") #Html.AntiForgeryToken()
// MyObjA part
#Html.LabelFor(model => model.Name):
#Html.TextBoxFor(model => model.Name)
#Html.ValidationMessage("Name", "*")
// MyObjB part
#Html.LabelFor(model => model.MyObjB.Name):
#Html.TextBoxFor(model => model.MyObjB.Name)
#Html.ValidationMessage("MyObjB.Name", "*")
#{ Html.EndForm(); }
The EnableClientValidation will not work....
I think this is related with the "." (dot) used and problems with the javacript, but I can be wrong and the cause be different.
If I do the same form but only for the MyObjB, it will work fine and the ClientValidation is done correctly.
How do you people use EnableClientValidation with subproperties?
Thank you.
EDIT 1 - For byte request
View:
#Html.TextBoxFor(model => model.MyObjB.Name)
HTML Result:
<input id="MyObjB_Name" name="MyObjB.Name" type="text" value="" />
I think you must use following in you web.config:
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
It will work as long as you have the reference and initialization of objB in objA, because your model to the view is ObjA
what you need to do is create a viewmodel for your view
which will have properties of Class A and Class B
public class ViewModelAB
{
[validation error message]
A PropertyA { get; set; }
[validation error message]
B PropertyB { get; set;}
}
and use this viewmodel model strogly types to your view