Why isn't my jQuery validation working? - asp.net-mvc

I have this in my Web.config:
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
My view model:
public class CustomerViewModel
{
public Guid Id { get; set; }
[Required]
[DisplayName("First Name")]
public string FirstName { get; set; }
}
My view:
#using (Html.BeginForm(MVC.Customers.Edit(), FormMethod.Post, new { id = "edit-customer" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(model => model.FirstName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
</div>
...
</div>
}
And this is how the "form-group" div gets rendered:
<div class="form-group">
<label class="control-label col-md-2" for="FirstName">First Name</label>
<div class="col-md-10">
<input id="FirstName" class="form-control text-box single-line" name="FirstName" value="" type="text" data-val-required="The First Name field is required." data-val="true">
<span class="field-validation-valid text-danger" data-valmsg-replace="true" data-valmsg-for="FirstName"></span>
</div>
</div>
And I'm loading the jQuery scripts in this order:
<script src="/Scripts/jquery-1.10.2.js"></script>
<script src="/Scripts/jquery-ui-1.10.4.js"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
The form is shown using an ajax call when a button is clicked. It is also submitted with ajax. This all works fine when I'm not doing any validation. I added validation and I can't get it to trigger before the ajax call. Here's what I'm doing in the click handler that submits the form:
var formToSubmit = $('#' + attrData.formIdToSubmit);
if (!formToSubmit.valid()) {
return false;
}
formData = formToSubmit.serialize();
...
I expect formToSubmit.valid() to trigger the validation and return false when nothing is entered in the FirstName field. In practice it returns true and then validation fails on the server, ModelState.IsValid returns false as expected. In looking through the jQuery validation docs it looks like it expects a required attribute, like this:
<input id="FirstName" class="form-control text-box single-line" name="FirstName" value="" type="text" data-val-required="The First Name field is required." data-val="true" required>
If I use dev tools to add that and then click the submit button then the call to formToSubmit.valid() returns false as expected, however the error message doesn't end up in the span created by #Html.ValidationMessageFor, it ends up in a newly added label that looks like this:
<label for="FirstName" class="error">This field is required.</label>
What am I doing wrong?

Here is how I ended up fixing it:
var formToSubmit = $('#' + attrData.formIdToSubmit);
formToSubmit.removeData("validator")
.removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse(formToSubmit);
if (!formToSubmit.valid()) {
return;
}
formData = formToSubmit.serialize();
...

Related

ASP.NET MVC hidden field still getting name and passing to controller

I have this control that is hidden and the user need to check the input control for it to be show. I am getting the model fill with data and I wanted to see how I can only get data in the controller if it is selected ?
View
<input type="checkbox" value="91" name="chkProduct">
<label>Other</label>
<input type="hidden">
<input type="hidden" asp-for="Other">
<div id="sourceSection_91" style="">
<div class="row" id="ddRow_6" data-source="sourceSection_91">
<div class="col-md-11 !important">
<div class="form-group">
<label class="control-label source-label">Other</label>
<input class="form-control" id="enteredOtherSource" name="enteredOtherSource[0].Other" type="text" value="">
<span class="field-validation-valid text-danger" data-valmsg-for="enteredOtherSource[0].Other" data-valmsg-replace="true"></span>
<input value="91" data-val="true" data-val-number="The field SourceId must be a number." data-val-required="The SourceId field is required." id="SourceId" name="enteredOtherSource[0].SourceId" type="hidden">
</div>
</div>
<div class="col-md-1 deleteBtn">
</div>
</div>
Model
public class OtherSourceModel
{
public int SourceId { get; set; }
public string Other { get; set; }
}
Controller
foreach (var ordermaterial in model.enteredOtherSource)
{
ProjectMaterialUse _SelectedOtherProjectMaterial = new ProjectMaterialUse();
_SelectedOtherProjectMaterial.Source = new Values();
_SelectedOtherProjectMaterial.Source.Value = ordermaterial.SourceId;
_SelectedOtherProjectMaterial.Other = ordermaterial.Other;
_SelectedOtherProjectMaterial.IntendedUse = new Values();
_SelectedOtherProjectMaterial.IntendedUse = model.selectedIntendedUseId;
_permissionrequestWeb.SelectedProjectMaterial.Add(_SelectedOtherProjectMaterial);
}

How to validate a duplicate post request from a form in MVC

I am having an form which insert a record whenever a post request is made,but the problem is that if someone clicks submit button more than 1 times than duplicate post request are made and at the end same records are getting inserted. I dont want to check that the record is already present or not because the record would be different always. I tried using ValidateAntiForgeryToken filter in controller but it is failing to validate the requests, Below is my View Code.
#using (Html.BeginForm("Create", "Home",FormMethod.Post,new { onkeydown = "return event.keyCode!=13" }))
{
#Html.AntiForgeryToken()
<div class="right-col">
#Html.TextBoxFor(model => model.Name, new { placeholder = "Name", #class = "small-box" })
</div>
<div class="left-col">Email Id :</div>
<div class="right-col">
#Html.TextBoxFor(model => model.EmailId, new { placeholder = "Email Id", #class = "small-box",id="resumeemailid" })
#Html.ValidationMessageFor(model => model.EmailId)
</div>
<div class="left-col">Address :</div>
<div class="right-col">
#Html.TextAreaFor(model => model.Address, new { placeholder = "Address", #class = "small-box" })
</div>
<div class="buttons resume-threebutton">
<input type="submit" id="register-button" class="gradient-btn" value="#T("Account.Passport.Register.Button.Upload", "Upload")" name="Command" />
<input type="submit" id="register-button" class="gradient-btn" value="#T("Account.Passport.Button.UploadandAdd", "Upload And Add New")" name="Command" />
<input type="button" id="register-button" class="gradient-btn" value="#T("Account.Passport.Register.Button.Cancel", "cancel")" name="register-button" onclick="location.href='#Url.Action("SelectTemplate", "CustomerTemplate")'" />
</div>
}
and below is my controller Post method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ProductModel model)
{
//To do add the product here...
}

Validation in .net MVC

I need to check whether all fields are filled while clicking insert button.
This is my view:
<body>
<form name="form1">
<h2>MEDICATION</h2>
<div class="med">
<pre>
<label>Patient code</label> <input type="text" id="pat" name="ptcode" size="25" value="" /> <label>ICD10</label> <input style="width:85px;height:30px;" type="text" name="icd10" value=""> <button style="height:30px;width:59px;" name="search" onclick="openicd()";>search</button><br />
<label>Medication</label> #Html.DropDownListFor(Model => Model.medication, Model.medication,"Select Medication", new { style = "width:200px; height :30px" }) <button style="height:30px;"onclick="openmedication()";>search</button> Prescription Date <input type="date" class="sizetestdate" name="testdate" style="width:140px;height:30px;" value="">
<label>Strength</label> #Html.DropDownListFor(Model => Model.strength, Model.strength, "Select Strength", new { style = "width:200px; height :30px" }) Start Date <input type="date" class="sizetestdate" name="testdate" style="width:140px;height:30px;" value=""> End Date <input type="date" class="sizetestdate" name="testdate" style="width:140px;height:30px;" value=""><br />
<label>Form</label> #Html.DropDownListFor(Model => Model.form, Model.form, "Select form", new { style = "width:200px; height :30px" }) Renewal Date <input type="date" class="sizetestdate" name="testdate" style="width:140px;height:30px;" value=""><label> Days Supply</label> <input type="text" style="width:85px;height:30px;" name="supply" value=""> <br />
<label>Route</label> #Html.DropDownListFor(Model => Model.route, Model.route, "Select route", new { style = "width:200px; height :30px" }) <label>Pharmacy</label> #Html.DropDownListFor(Model => Model.pharmacy, Model.pharmacy, "Select Pharmacy", new { style = "width:200px; height :30px" })<br />
<label>Dose</label> #Html.DropDownListFor(Model => Model.dosage, Model.dosage, "Select Dose", new { style = "width:200px; height :30px" })
</pre>
</div>
</form>
<hr />
<div class="wrapper">
<button class="button" style="height:30px;" id="a" >Insert</button> <button class="button" style="height:30px;" id="b">Update</button> <button class="button" style="height:30px;" id="c">Delete</button>
</div></body>
</html>
The best way is adding model Validations in Models
i don't know how your model look like assuming
public class Meditation
{
[Required]
public int id{get;set}
[Required]
public int name{get;set;}
}
using System.ComponentModel.DataAnnotations; should be added
or you can simply use required in form
<input type="text" style="width:85px;height:30px;" name="supply" value="" required>
#Html.DropDownListFor(Model => Model.dosage, Model.dosage, "Select Dose", new { style = "width:200px; height :30px", #required="true"})
You can use your model for validation
public class Example {
public int id { get; set; }
[Required]
public string name { get; set; }
}
view more - Microsoft Docs

Dynamically added elements validation error

I've put some Regex expression on the properties of my model that only accept numbers.
public class MaterialsViewModel
{
[Display(Name = "Material")]
public string MaterialName { get; set; }
[Range(typeof(int), "0", "999")]
[RegularExpression(#"^\d+$", ErrorMessage = "Please enter proper value")]
public int? Quantity { get; set; }
[RegularExpression(#"^\d+$", ErrorMessage = "Please enter proper value")]
public double? Cost { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
public int SelectedCategory { get; set; }
public string SelectedCategoryName { get; set; }
}
I have my View in which I can add controls dynamically
Dynamically add ScopeOfWork and Materials<br />
<div id="scopes">
<h3>Scopes</h3>
Add Scope of Work
#for (int i = 0; i < Model.ScopeOfWork.Count; i++)
{
<div class="scope">
<div class="form-group">
#Html.LabelFor(m => m.ScopeOfWork[i].ScopeOfWorkName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.ScopeOfWork[i].ScopeOfWorkName, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.ScopeOfWork[i].ScopeOfWorkName)
</div>
</div>
<input type="hidden" class="scopeindex" name="ScopeOfWork.Index" value="#i" />
<div class="indent materials">
<h4>Material</h4>
Add Material
#for (int j = 0; j < Model.ScopeOfWork[i].Materials.Count; j++)
{
<div class="material">
<div class="form-group">
#Html.LabelFor(m => m.ScopeOfWork[i].Materials[j].MaterialName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-2">
#Html.TextBoxFor(m => m.ScopeOfWork[i].Materials[j].MaterialName, new { #class = "form-control" })
</div>
<div class="col-md-10 col-md-offset-2">
#Html.ValidationMessageFor(m => m.ScopeOfWork[i].Materials[j].MaterialName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ScopeOfWork[i].Materials[j].Quantity, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-1">
#Html.TextBoxFor(m => m.ScopeOfWork[i].Materials[j].Quantity, new { #class = "form-control" })
</div>
<div class="col-md-10 col-md-offset-2">
#Html.ValidationMessageFor(m => m.ScopeOfWork[i].Materials[j].Quantity)
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ScopeOfWork[i].Materials[j].Cost, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-1">
#Html.TextBoxFor(m => m.ScopeOfWork[i].Materials[j].Cost, new { #class = "form-control" })
</div>
<div class="col-md-10 col-md-offset-2">
#Html.ValidationMessageFor(m => m.ScopeOfWork[i].Materials[j].Cost)
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2">Category</label>
<div class="col-xs-2">
#Html.DropDownListFor(m => m.ScopeOfWork[i].Materials[j].SelectedCategory, Model.ScopeOfWork[i].Materials[j].CategoryList, "Please select", htmlAttributes: new { #class = "form-control" })
</div>
</div>
<input type="hidden" class="materialindex" name="ScopeOfWork[#i].Materials.Index" value="#j" />
</div>
}
</div>
</div>
}
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-success" />
</div>
</div>
</div>
}
<div id="newScope" style="display:none">
<div class="scope">
<div class="form-group">
<label for="_#__ScopeOfWorkName" class="control-label col-md-2">Scope Of Work</label>
<div class="col-md-10">
<input class="form-control" type="text" id="_#__ScopeOfWorkName" name="ScopeOfWork[#].ScopeOfWorkName" value="">
<span class="field-validation-valid text-danger" data-valmsg-for="ScopeOfWork[#].ScopeOfWorkName" data-valmsg-replace="true"></span>
</div>
</div>
<input type="hidden" class="scopeindex" name="ScopeOfWork.Index" value="#" />
<div class="materials">
<h4>Material</h4>
Add Material
</div>
<hr />
</div>
</div>
<div id="newMaterial" style="display:none">
<div class="form-group">
<label for="_#__Materials_%__MaterialName" class="control-label col-md-2">Material</label>
<div class="col-md-2">
<input class="form-control" type="text" id="_#__Materials_%__MaterialName" name="ScopeOfWork[#].Materials[%].MaterialName" value="">
<span class="field-validation-valid text-danger" data-valmsg-for="ScopeOfWork[#].Materials[%].MaterialName" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label for="_#__Materials_%__Quantity" class="control-label col-md-2">Quantity</label>
<div class="col-md-1">
<input class="form-control" type="text" id="_#__Materials_%__Quantity" name="ScopeOfWork[#].Materials[%].Quantity" value="">
<span class="field-validation-valid text-danger" data-valmsg-for="ScopeOfWork[#].Materials[%].Quantity" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label for="_#__Materials_%__Cost" class="control-label col-md-2">Cost</label>
<div class="col-md-1">
<input class="form-control" type="text" id="_#__Materials_%__Cost" name="ScopeOfWork[#].Materials[%].Cost" value="">
<span class="field-validation-valid text-danger" data-valmsg-for="ScopeOfWork[#].Materials[%].Cost" data-valmsg-replace="true"></span>
</div>
</div>
#*Drop down*#
<div class="form-group">
<label for="_#__Materials_%__SelectedCategory" class="control-label col-md-2">Category</label>
<div class="col-xs-2">
<select class="form-control category" id="_#__Materials_%__SelectedCategory" name="ScopeOfWork[#].Materials[%].SelectedCategory">
<option value="">--Select--</option>
</select>
</div>
</div>
<input type="hidden" class="materialindex" name="ScopeOfWork[#].Materials.Index" value="%" />
</div>
<script>
var form = $('form');
var scope = $('#newScope');
var material = $('#newMaterial');
var categories = #Html.Raw(Json.Encode(Model.CategoryList));
form.on('click', '.addmaterial', function () {
var clone = material.clone();
var scopeIndex = $(this).closest('.scope').find('.scopeindex').val();
clone.html($(clone).html().replace(/#/g, scopeIndex));
var materialIndex = new Date().getTime();
clone.html($(clone).html().replace(/%/g, materialIndex));
// drop down list
var select = clone.find('.category');
$.each(categories, function(index, item) {
select.append($('<option></option>').val(item.Value).text(item.Text));
});
$(this).closest('.materials').append(clone.html());
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});
$('#addScope').click(function () {
var clone = scope.clone();
var scopeIndex = new Date().getTime();
clone.html($(clone).html().replace(/#/g, scopeIndex));
$('#scopes').append(clone.html());
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});
</script>
Controller:
[HttpPost]
public ActionResult _CreateProject(ProjectViewModel project)
{
tblProject projectModel = new tblProject();
tblScopeOfWork scopeModel = new tblScopeOfWork();
tblMaterial materialModel = new tblMaterial();
if (ModelState.IsValid)
{
projectModel.ProjectName = project.ProjectName;
projectModel.ProjectLocation = project.ProjectLocation;
projectModel.ProjectDescription = project.ProjectDescription;
projectModel.WorkArea = project.WorkArea;
projectModel.ModeOfPayment = project.ModeOfPayment;
projectModel.Duration = project.Duration;
projectModel.StartDate = project.StartDate;
projectModel.EndDate = project.EndDate;
projectModel.ProfitSupervision = project.ProfitSupervision;
projectModel.ProjectStatus = project.ProjectStatus;
projectModel.ForemanId = project.ForemanId;
projectModel.ClientId = project.ClientId;
db.tblProjects.Add(projectModel);
db.SaveChanges();
//Get the recently created ProjectId
var recentProjectId = db.tblProjects.OrderByDescending(x => x.ProjectId).FirstOrDefault().ProjectId;
//Get all values from List of ScopeOfWork
//Add each ScopeOfWork to the database
for (int scopeIndex = 0; scopeIndex < project.ScopeOfWork.Count; scopeIndex++)
{
scopeModel = new tblScopeOfWork();
scopeModel.ScopeOfWork = project.ScopeOfWork[scopeIndex].ScopeOfWorkName;
scopeModel.ProjectId = recentProjectId;
db.tblScopeOfWorks.Add(scopeModel);
db.SaveChanges();
//Get the recently created ScopeOfWorkId
var recentScopeOfWorkId = db.tblScopeOfWorks.OrderByDescending(x => x.ScopeOfWorkId).FirstOrDefault().ScopeOfWorkId;
//Get all materials from its corresponding ScopeOfWork and save to database
for (int materialIndex = 0; materialIndex < project.ScopeOfWork[scopeIndex].Materials.Count; materialIndex++)
{
materialModel = new tblMaterial();
materialModel.Description = project.ScopeOfWork[scopeIndex].Materials[materialIndex].MaterialName;
materialModel.Quantity = project.ScopeOfWork[scopeIndex].Materials[materialIndex].Quantity;
materialModel.Cost = project.ScopeOfWork[scopeIndex].Materials[materialIndex].Cost;
materialModel.ScopeOfWorkId = recentScopeOfWorkId;
materialModel.CategoryId = project.ScopeOfWork[scopeIndex].Materials[materialIndex].SelectedCategory;
db.tblMaterials.Add(materialModel);
}
}
db.SaveChanges();
}
project.ScopeOfWork = new List<ScopeOfWorkViewModel>
{
new ScopeOfWorkViewModel()
{
Materials = new List<MaterialsViewModel>
{
new MaterialsViewModel()
{
CategoryList = new SelectList(db.tblCategories, "CategoryId", "CategoryName")
}
}
}
};
return View(project);
}
}
The problem is I tried to put some string ('ss') on the textbox of quantity and cost to see if the validation will work and this appears The value 'ss' is not valid for Quantity and The value 'ss is not valid for Cost.but it should be Please enter proper value. And also whenever the validation occurs, the Add Material link cannot add another newMaterial.
I have tried and check these answer and also DotNetFiddle but still it has some errors.
You do not need your regex (its an int so it can only accept a number anyway). And ditto for the cost property (but why have you made it decimal if you don't allow fractions?).
The validation for the type will be performed first, and because its invalid, no further validation is performed.
Change the attribute to to a [Required]
[Range(typeof(int), "0", "999")]
[Required(ErrorMessage = "Please enter proper value")]
public int? Quantity { get; set; }
Refer also this question/answer for changing the default error message for an invalid value for a type.
As a side note, your dynamically added items will not give client side validation because you have not added the necessary data-val-* attributes. You need to inspect the html generated for the elements in the for loops and copy the html exactly, except replacing the collection indexers.
You also have an issue with your POST method because you set the ScopeOfWork property to a new collection, and wipe out all the data the user has entered before you return the view. The basic structure of your POST method should be
[HttpPost]
public ActionResult _CreateProject(ProjectViewModel project)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(project);
return View(project);
}
// code to initialize your data models, save and redirect
}
private void ConfigureViewModel(ProjectViewModel model)
{
var categories = db.tblCategories;
model.CategoryList = new SelectList(categories , "CategoryId", "CategoryName");
foreach (var scope in model.ScopeOfWork)
{
foreach (var material in scope.Materials)
{
material.CategoryList = new SelectList(categories , "CategoryId", "CategoryName");
}
}
}
Note the ConfigureviewModel() method is also called from your GET method to populate the SelectLists

button cannot trigger in mvc 4

I am having some trouble in ASP.NET MVC4 - When I click the Login button it's not hitting my controller and not logging in
This is the code on my .cshtml
#using System.Linq
<body>
<div class="container">
#using (Html.BeginForm("Login", "Login", FormMethod.Post, new { #Class = "form-signin", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "Login failed. Check your login details.")
<img class="img-responsive" src="~/Images/PI%20Logo.jpg" />
#Html.TextBoxFor(m => m.userName, new {#Class = "form-control", #Id = "user", #placeholder = "Username"})
#Html.ValidationMessageFor(m => m.userName)
#Html.PasswordFor(p => p.passwd, new {#Class = "form-control", #Id = "pass", #placeholder = "Password"})
#Html.ValidationMessageFor(m => m.passwd)
<!--<input class="form-control" id="username" placeholder="Username" type="text" />
<input class="form-control" id="Password1" placeholder="Password" type="password" /> -->
<input id="submit" class="btn btn-lg btn-primary btn-block" type="button" value="LOGIN" />
}
</div>
<script src="~/Scripts/jquery-1.11.2.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
</body>
and this is my controller
public class LoginController : Controller
{
//
// GET: /Login/
public ActionResult Login()
{
return View();
}
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Login(Login login)
{
AccountManagement am = new AccountManagement();
var xrm = new XrmServiceContext("Xrm");
SystemUser sysUser = xrm.SystemUserSet.Where(x => x.DomainName == "hc\\" + login.userName && x.IsDisabled == false).FirstOrDefault();
if (am.ValidateCredentials(login.userName, login.passwd) == "True" && sysUser != null)
{
Session["username"] = login.userName;
return RedirectToAction("MainHome", "MainMenu");//Request.CreateResponse(HttpStatusCode.OK, new { Message = "Success", User = sysUser });
}
else
{
ModelState.AddModelError("", "Login data is incorrect!");//Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Username or Password Invalid");
}
return View(login);
}
}
What's wrong with my code - i'm so confused, because many tutorial made simple login like this but it's work
Change button type to submit
<input id="submit" class="btn btn-lg btn-primary btn-block" type="submit" value="LOGIN" />
Difference between input type Button & submit
<input type="button" />
buttons will not submit a form - they don't do anything by default. They're generally used in conjunction with JavaScript as part of an AJAX application.
<input type="submit">
buttons will submit the form they are in when the user clicks on them, unless you specify otherwise with JavaScript.

Resources