In this blog, we will implement remote validation by making an ajax call to the server without using jQuery; we will achieve this using vanilla JavaScript.
What is the purpose of remote validation?
Here’s an explanation: Often, user inputs must be checked against a database to see if it already exists. We need to validate the input on the client side. We must achieve this without posting the entire form to the server. In such a scenario, a server call is necessary to confirm the uniqueness of the entered data. A username, for example, must be unique when creating a new user.
Remote Validation
ASP.NET MVC 3 provides the mechanism for performing remote validation. ASP.NET MVC’s remote validation depends heavily on the jQuery and jQuery.Validate libraries. Remote validation makes an ajax call to the server using jQuery.
Let’s start with model.
Here’s my user model having Id, Username, and Password properties.
namespace ASP.Net_MVC.Models { [Table("Users")] public class User { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] [Key] public int Id { get; set; } [Required(ErrorMessage = "This username is required.")] public string UserName { get; set; } [Required(ErrorMessage = "This password is required.")] public string Password { get; set; } } }
CheckExistingUser action method is called when a user clicks a create button.
namespace ASP.Net_MVC.Controllers { public class UserController : Controller { EmployeeContext _userService = new EmployeeContext(); // GET: User public ActionResult Create() { return View(); } [HttpPost] public ActionResult Create(User user) { if (ModelState.IsValid) { _userService.Users.Add(user); _userService.SaveChanges(); return RedirectToAction("Index"); } return View(user); } [AcceptVerbs("GET", "POST")] public ActionResult CheckExistingUser(string userName) { if (!_userService.Users.Any(u => u.UserName == userName)) { return HttpNotFound(); } return new HttpStatusCodeResult(200, $"A user {userName} already exists."); }
Create.cshtml (View)
On form submission, JavaScript onsubmit event gets called, which in turn calls a JavaScript function validateForm(). We are embedding a URL to an action method by specifying the action and controller names in the Url.Action method().
@model ASP.Net_MVC.Models.User @{ ViewBag.Title = "Create User"; } <form asp-controller="User" asp-action="Create" id="form-submit" method="post" onsubmit="return validateForm('@Url.Action("CheckExistingUser","User", null)', event)"> @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Create User</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <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.Password, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" }) </div> </div> <div class="error-div"> <label id="errormessage" class="text-danger"></label> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div> </form> <div> @Html.ActionLink("Back to List", "Index") </div>
JavaScript function to validate user
In the JavaScript validateForm() function, we split the URL and get the action method. We are splitting the URL as it can be reused for other action methods. We could get other DOM elements specific to each action method and reuse the same ajax call to send the fields to the action method and check for data uniqueness. From the controller action method, we receive a response, and based on that, we either display the validation error message to the user or submit the form.
If this method returns response code 404 NotFound, the username does not exist, and the form gets submitted; otherwise, the method returns response code 200 OK, a user already exists. The submitted form calls the create method, which adds the user to the database.
Note: The parameter name (userName) must match the parameter name in the appended query string of the URL in JavaScript.
function validateForm(url, event) { event.preventDefault(); let splits = url.split('/'); let action = splits[splits.length - 1]; if (action.includes("CheckExistingUser")) { console.log(action); let userName = document.getElementById("UserName").value url += `?userName=${userName}` } var xhttp = new XMLHttpRequest(); xhttp.open("GET", url, true); xhttp.send(); xhttp.onreadystatechange = function (event) { if (this.readyState == 4 && this.status == 200) { document.getElementById("errormessage").innerHTML = this.statusText; } else if (this.readyState == 4 && this.status == 404) { document.querySelector("#form-submit").submit(); } }; }
The same ajax call is extended to include additional action methods. We can also check multiple fields on a form by retrieving them from the DOM and passing them via URL.
function validateForm(url, event) { event.preventDefault(); let splits = url.split('/'); let action = splits[splits.length - 1]; if (action.includes("CheckExistingUser")) { let userName = document.getElementById("UserName").value let pswd = document.getElementById("Password").value url += `?userName=${userName}&password=${pswd}` } else if (action.includes("CheckExistingEmployee")) { let employeeId = document.getElementById("EmployeeId").value let email = document.getElementById("Email").value url += `?EmployeeId=${employeeId}&Email=${email}` } else {} var xhttp = new XMLHttpRequest(); xhttp.open("GET", url, true); xhttp.send(); xhttp.onreadystatechange = function (event) { if (this.readyState == 4 && this.status == 200) { document.getElementById("errormessage").innerHTML = this.statusText; } else if (this.readyState == 4 && this.status == 404) { document.querySelector("#form-submit").submit(); } }; }
For the above scenario, the controller action method will look like this:
[AcceptVerbs("GET", "POST")] public IActionResult CheckExistingEmployee(int EmployeeId, string Email) { if (!_employeeService.Employees.Any(u => u.EmployeeId == EmployeeId && u.Email == Email)) { return HttpNotFound(); } return new HttpStatusCodeResult(200, $"Employee {Email} already exists."); }
Hope you will find this blog helpful. (By writing 20 -25 lines of JavaScript, we have avoided the use of jQuery and jQuery validate libraries)