How to make this ASP.NET Core Model Validation work on client-side?

2.4k views Asked by At

In my ASP.NET Core 1.1.1 app the following Model Validation is not working. I think the issue is related to me not properly adding validation scripts in Main View below.

Scenario:

  1. I click on a button on Main View that calls a partial view.
  2. I enter all correct values, in partial view and submit the form (in partial view), the form successfully gets submitted and all the values are correctly entered into SQL server db.
  3. I then intentionally enter a string, say, abc into the input box for price (that is of nullable type float) and submit the form. A client side error does NOT show up even (the javascript is enabled on my Chrome browser). Hence, Form gets submitted to the server where ModeState.IsValid, as expected, is false in the POST action method.

Question: Why client-side validation (as shown in step 3) above is not working and how we can make it work?

Note: All the css and javascripts were added and configured by default by VS2017 when the project was created. So I think scripts are all there and I may not be calling them correctly on the views - but that's just an assumption.

MyViewModel

public class MyViewModel
{
    public int FY { get; set; } 
    public byte OrderType { get; set; }
    public float? Price { get; set; } 
    ....
}

Main View

@model MyProj.Models.MainViewModel

...
<div>
  <button type="submit" name="submit"...>GO</button>
</div
@section scripts
{
  <script>
    $(document).ready(function () {
     ....
     $('.tab-content').on('click', '.BtnGO', function (event) {
    ....    
    $.ajax({
        url: '@Url.Action("SU_AddCustOrder", "MyContr")',
        data: { ....},
        contentType: 'application/json',
        dataType: 'html',
        type: 'GET',
        cache: false,
        success: function (data) {
            if (BtnVal == 'AddOrderBtnGo')
                $('#menuAP').html(data);
            else if ....
        error: function (....){
              alert(...);
        }
    });
});

MyContrController:

[HttpGet]
public IActionResult AddCustOrder(int Order_id)
{
 ....
 return PartialView("~/Views/PartialsV/MyPartialView.cshtml", myVM);
 ....
}

[HttpPost]
public IActionResult AddCustOrder(MyViewModel model)
{
 ....
 if(ModelState.IsValid)
 {
   ....
 }
 ....
}

Partial View

....
<div class="form-group">
    <label asp-for="Price"></label>
    <div class="col-md-10">
        <input asp-for="Price" class="form-control"></input>
        <span asp-validation-for="Price" class="text-danger"></span>
    </div>
</div>
....
<button type="submit" name="submit"...>Add Order</button>

UPDATE

_layout.cshtm file

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Test</title>

    <environment names="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>
    <environment names="Staging,Production">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
    </environment>
    @RenderSection("styles", required:false)
</head>
<body>
    <header>
        <div class="container navbar navbar-inverse navbar-fixed-top text-center">
        </div>
        <div class="container nav nav-pills" style="margin-top:4px;background-color:cornsilk;">
            @await Component.InvokeAsync("Welcome")
        </div>
    </header>
    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer class="text-center">
            <a asp-controller="Misc" asp-action="AccessibilityStatement" class="text-center text-muted">Accessibility Statement</a>
        </footer>
    </div>

    <environment names="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    </environment>
    <environment names="Staging,Production">
        <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                asp-fallback-test="window.jQuery">
        </script>
        <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
        </script>
        <script src="~/js/site.min.js" asp-append-version="true"></script>
    </environment>

    @RenderSection("scripts", required: false)
    @RenderSection("css", required:false)
</body>
</html>
1

There are 1 answers

1
Ali On BEST ANSWER

I see. If you go and open Shared folder inside Views folder you will find a file called _ValidationScriptsPartial.cshtml that contains the validation scripts.

Now the first thing to do is to add validation attributes such as [Required] to your view model.

Than in Main View add @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } before <script>.

After you add the html of the partial view in this line $('#menuAP').html(data);, find the form and call $.validator.unobtrusive.parse() like the following

if (BtnVal == 'AddOrderBtnGo') {
   $('#menuAP').html(data);
   var $form = $('#menuAP').find('#your-form-id-here');
   $.validator.unobtrusive.parse($form);
}