Razor Pages - Unobtrusive Validation Issue

5 posts, 0 answers
  1. Arturs
    Arturs avatar
    3 posts
    Member since:
    Nov 2017

    Posted 12 Mar 2020 Link to this post

    Hey,

    So I've been using the asp.net core kendo and it is great but I cannot seem to get over one hurdle and that is the validation.

    I have extended the kendo validation to include remote validation to check if a field name exists in the database already, that all works fine but the problem currently is that if I include the jQuery validation and jQuery unobtrusive validation into my scripts I would get 404 errors every time I type something into the text box (because the remote url passed down is different on unobtrusive than on kendo validation). I have attached an image of the 404 error I am getting.

    But if I remove jQuery validation and jQuery unobtrusive I get no errors but because of the nature of razor pages the kendo remote validation does not register to the model and so even if the remote validation failed, the field is updated/added.

    app.js

    "use strict";
     
    import gridFunctions from "./js/gridFunctions";
     
    // Top level packages that need to be initiated first
    import $ from "../node_modules/jquery/dist/jquery";
    window.jQuery = $;
    window.$ = $;
    gridFunctions();
     
    // Scss
    import "./scss/app.scss";
     
    // Add all kendo
    import "@progress/kendo-ui";
    import "@progress/kendo-ui/js/kendo.aspnetmvc";
    import "@popperjs/core";
     
    // Add jquery validation
    import "jquery-validation/dist/jquery.validate";
    import "jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive";
     
    // Add boostrap js
    import "@popperjs/core/dist/cjs/popper";
    import "bootstrap/dist/js/bootstrap.bundle";
     
    // Add Font Awesome
    import "@fortawesome/fontawesome-free/js/all";
     
    $.validator.setDefaults({
        ignore: ""
    });

     

    Edit.cshtml

     <form method="post">
        <input type="hidden" asp-for="@Model.SystemRole.SystemRoleId" />
     
        @* Inputs *@
        <div class="row">
            <div class="col-sm-3">
                <div class="input-outer">
                    <label asp-for="@Model.SystemRole.SystemRoleDesc" class="required"></label>
                    <input asp-for="@Model.SystemRole.SystemRoleDesc"
                           data-val-remote-additionalfields="SystemRoleDesc"
                           data-val-remote-url="CheckSystemRoleDescExists"
                           class="k-textbox" />
                    <span asp-validation-for="@Model.SystemRole.SystemRoleDesc"></span>
                </div>
     
                <div class="input-outer">
                    <label asp-for="@Model.SystemRole.SystemRoleRef" class="required"></label>
                    <input asp-for="@Model.SystemRole.SystemRoleRef"
                           data-val-remote-additionalfields="SystemRoleRef"
                           data-val-remote-url="CheckSystemRoleRefExists"
                           class="k-textbox" />
                    <span asp-validation-for="@Model.SystemRole.SystemRoleRef"></span>
                </div>
     
                <div class="input-outer">
                    <label asp-for="@Model.SystemRole.IsDeleted"></label>
                    <input asp-for="@Model.SystemRole.IsDeleted" type="checkbox" data-validate="false" class="k-checkbox">
                    <span asp-validation-for="@Model.SystemRole.IsDeleted"></span>
                </div>
            </div>
            <div class="col-sm-3"></div>
            <div class="col-sm-3"></div>
            <div class="col-sm-3"></div>
        </div>
     
        <hr />
     
        @* Buttons *@
     
        <input type="submit" value="Update" class="btn btn-primary" />
     
    </form>
     

     

    Any help is really appreciated! 

    Thank you.

  2. Aleksandar
    Admin
    Aleksandar avatar
    242 posts

    Posted 17 Mar 2020 Link to this post

    Hello Arturs,

    To use the Kendo validator it needs to be added to the Form that needs to be validated:

    <form method="post" kendo-validator="true" id="myform">
    ...
    </form>

    Then validate the form on submit:

    var validator = $("#myform").data("kendoValidator");
    
            $("form").submit(function (event) {
                event.preventDefault();
                validator.validate()
            });

    In regards to the remote validation, I would assume the following guideline was followed - Implement Remote Validation. In this scenario update the remote url to the page handler performing the validation

    <form method="post" kendo-validator="true" id="myform">
        <input asp-for="Email" />
        <span asp-validation-for="Email" data-val-remote-url="@Url.PageLink("Index","CheckEmail")"></span><br>
        <input type="submit" />
    </form>
     Update the ajax request so that the input elements are sent as FromData:


    var postData = new FormData(document.getElementById("myform"));
    $.ajax({
        url: url,
        type: "POST",
        data: postData,
        cache: false,
        processData: false,
        contentType: false,
        dataType: "json",
        success: function (data) {
          ...
        },
        error: function (data) {
          ...
        }
    });

    The Page handler would perform the validation and return an error message if the validation fails:

    public JsonResult OnPostCheckEmail()
            {
                var existingEmails = new[] { "jane@test.com", "claire@test.com", "dave@test.com" };
                var valid = !existingEmails.Contains(Email);
                if (!valid)
                {
                    return new JsonResult("This Email already exists");
                }
                return new JsonResult(valid);
            }

    Finally, the property would be decorated with the BindProperty attribute and PageRemote attribute:

            [PageRemote(
                AdditionalFields = "__RequestVerificationToken",
                HttpMethod = "Post",
                PageHandler = "CheckEmail"
            )]
            [BindProperty]
            [Required]
            public string Email { get; set; }

    Upon submission of an existing email the remote validation would be triggered:

    Attached is a sample ASP.NET Core solution with the above implemented. I hope this helps implement the desired functionality in the application. Let me know if you have additional questions.

    Regards,
    Aleksandar
    Progress Telerik

    Get quickly onboarded and successful with Telerik UI for ASP.NET Core with the dedicated Virtual Classroom technical training, available to all active customers.
  3. Arturs
    Arturs avatar
    3 posts
    Member since:
    Nov 2017

    Posted 20 Mar 2020 in reply to Aleksandar Link to this post

    Hi Aleksandar

    Thanks for your help, I do not have issue with setting up remote validation, all of that is working fine for me. My issue is that when remote validation is passed and I click the submit button (and because of event.preventDefault()) nothing gets submitted to the database and so no rows are saved.

    This has been my big roadblock and I've scoured every corner of the next looking for a solution. 

    Thanks

  4. Arturs
    Arturs avatar
    3 posts
    Member since:
    Nov 2017

    Posted 23 Mar 2020 Link to this post

    God, I am getting so frustrated with this validation crap.

     

    Look, I am able to remotely validate a value that checks the database and returns an error message which then gets appended to the data-val-remote attribute and the error is shown.

    BUT!!!!!!!!!!!!!!!!!!!

    I am still able to save because the validator.validate() always returns true!!!!

    SO the event.preventDefault() is not triggered even though the remote validation has failed!

    What the hell am I doing wrong here...................

  5. Aleksandar
    Admin
    Aleksandar avatar
    242 posts

    Posted 25 Mar 2020 Link to this post

    Hi Arturs,

    I have updated the initially provided example and made the following modifications so that when the form is valid it will be submitted to the respective handler. The first modification you could make is changing the input type of the form from "submit" to "button" and handle the button click event to validate the form:

    <form method="post" asp-page-handler="FormSubmit" kendo-validator="true" id="myform">
       ...
        <input id="btn" type="button" value="Submit" />
    </form>


    $("#btn").click(function (event) {
                event.preventDefault();
                var isFormValid = validator.validate();
                if (isFormValid) {
                    $('form').submit();
                } 
            });

    I further updated the remote validation logic and the server would return a bad request in case the validation is not successful and the respective validation message will be displayed: 

    public ActionResult OnPostCheckEmail()
            {
                var existingEmails = new[] { "jane@test.com", "claire@test.com", "dave@test.com" };
                var valid = !existingEmails.Contains(Email);
                if (!valid)
                {
                    return new StatusCodeResult(400);
                }
                return new JsonResult(new { Success = true });
            }


    $("#myform").kendoValidator({
            validateOnBlur: true,
            messages: {
                email: "This Email already exists",
            },
            rules: {
                email: function (input) {
                    return inputRule(input, "Email");
                }
            }
        });

    The inputRule function will check the validation state of the input and trigger remote validation. Check the attached updated project for further details.

    I hope this helps. Let me know if you have additional questions.

    Regards,
    Aleksandar
    Progress Telerik

    Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
    Our thoughts here at Progress are with those affected by the outbreak.
Back to Top