Tuesday, April 8, 2025

This jQuery code snippet is part of a form validation and user experience enhancement process, likely within an ASP.NET Core MVC application using jQuery and AJAX. It handles the scenario where a form submission is attempted but fails validation. Let’s break down its purpose and functionality step-by-step, contextualizing it within a .NET Core MVC jQuery AJAX call.

if (!form.valid()) {
        console.warn("Form is invalid. Please check the highlighted fields.");
        var firstError = $(form.find(".is-invalid, .input-validation-error")[0]);                   
        if (firstError.length > 0) {
            var tabPane = firstError.closest('.tab-pane');
            if (tabPane.length > 0 && !tabPane.hasClass('show')) {
                var tabId = tabPane.attr('id');
                var tabButton = $(`[data-bs-target="#${tabId}"]`);
                if (tabButton.length > 0) {
                    var tabInstance = bootstrap.Tab.getInstance(tabButton[0]) || new bootstrap.Tab(tabButton[0]);
                    tabInstance.show();

                    setTimeout(function () {
                        firstError.focus();
                        $('html, body').animate({
                            scrollTop: firstError.offset().top - 100             
                        }, 300);
                    }, 300);                      
                }
            } else {
                firstError.focus();
                $('html, body').animate({
                    scrollTop: firstError.offset().top - 100
                }, 300);
            }
        }
        if (typeof toastr !== 'undefined') {
            toastr.warning('Please correct the errors before saving.');
        } else {
            alert('Please correct the errors before saving.');
        }
        return false;                   
    }

The primary purpose of this code is to:
  1. Detect Form Validation Failure: Check if the form is invalid using form.valid() (from jQuery Validation).
  2. Highlight and Navigate to Errors: Identify the first invalid field, switch to its containing tab (if applicable), focus it, and scroll the page to it.
  3. Notify the User: Display a warning message (using toastr if available, or a fallback alert) to prompt the user to fix the errors.
  4. Prevent Submission: Return false to stop the form submission process (e.g., the AJAX call) until the form is valid.
This enhances the user experience by ensuring they’re aware of validation issues and can easily locate and correct them.


if (!form.valid())
  • form.valid(): This is a method from the jQuery Validation plugin. It checks if the form passes all client-side validation rules (e.g., required fields, email format, etc.).
  • !form.valid(): If the form is invalid, the condition is true, and the code inside the block executes.
  • Purpose: This is the entry point to handle validation failure. If the form is valid, this block is skipped, and the submission (e.g., AJAX call) can proceed.
2. console.warn("Form is invalid...")
  • Logs a warning to the browser console for debugging purposes, indicating that the form failed validation.
  • Purpose: Helps developers troubleshoot issues during development.
3. var firstError = $(form.find(".is-invalid, .input-validation-error")[0])
  • form.find(".is-invalid, .input-validation-error"): Searches the form for elements with the class is-invalid or input-validation-error. These classes are typically added by jQuery Validation or Bootstrap when a field fails validation.
  • [0]: Selects the first matching element (the first invalid field).
  • $(...): Wraps it in a jQuery object for further manipulation.
  • Purpose: Identifies the first field with a validation error so the code can focus the user’s attention on it.
4. if (firstError.length > 0)
  • Checks if there’s at least one invalid field.
  • Purpose: Ensures subsequent logic only runs if an error is found.
5. Tab Navigation Logic
var tabPane = firstError.closest('.tab-pane');
if (tabPane.length > 0 && !tabPane.hasClass('show')) {
    var tabId = tabPane.attr('id');
    var tabButton = $(`[data-bs-target="#${tabId}"]`);
    if (tabButton.length > 0) {
        var tabInstance = bootstrap.Tab.getInstance(tabButton[0]) || new bootstrap.Tab(tabButton[0]);
        tabInstance.show();
    }
}

  • firstError.closest('.tab-pane'): Finds the nearest ancestor with the class tab-pane (e.g., pills-gerais, pills-financeiros from your HTML), which represents the tab containing the invalid field.
  • !tabPane.hasClass('show'): Checks if the tab is not currently visible (Bootstrap uses show to indicate the active tab).
  • tabId: Gets the id of the tab pane (e.g., pills-gerais).
  • [data-bs-target="#${tabId}"]: Finds the tab button that activates this tab pane (e.g., the <button> with data-bs-target="#pills-gerais").
  • bootstrap.Tab.getInstance: Uses Bootstrap’s JavaScript API to get or create a Tab instance for the button.
  • tabInstance.show(): Switches to the tab containing the invalid field.
  • Purpose: Ensures the user sees the tab with the error if it’s not already active, which is critical in a multi-tab form like yours.
6. Focus and Scroll Logic
javascript:
setTimeout(function () {
    firstError.focus();
    $('html, body').animate({
        scrollTop: firstError.offset().top - 100
    }, 300);
}, 300);

  • setTimeout: Delays execution by 300ms to allow the tab switch animation to complete (Bootstrap’s tab transition takes time).
  • firstError.focus(): Sets keyboard focus on the invalid field, making it easier for the user to start typing.
  • $('html, body').animate(...): Smoothly scrolls the page to the invalid field’s position, offset by 100 pixels above it to account for headers or spacing.
  • Purpose: Guides the user directly to the problematic field, improving accessibility and usability.
7. Fallback Focus and Scroll (if no tab switch is needed)

javascript
} 
  • If the invalid field is already in the active tab (no tab switch needed), this block focuses and scrolls to it immediately.
  • Purpose: Handles cases where the error is in the currently visible tab.
8. User Notification

javascript

  } else {
   firstError.focus();
    $('html, body').animate({
        scrollTop: firstError.offset().top - 100300);
}
  • alert: Falls back to a native browser alert if Toastr isn’t available.
  • Purpose: Informs the user that the form can’t be submitted due to errors, prompting them to fix the highlighted fields.
9. return false
  • Returns false to halt further execution (e.g., prevent the AJAX call from proceeding).
  • Purpose: Stops the form submission process, ensuring invalid data isn’t sent to the server.


Example:
function saveCompanyDetail() {
    var form = $('#frmCompanyDetail');
    if (!form.valid()) {
        console.warn("Form is invalid. Please check the highlighted fields.");
        var firstError = $(form.find(".is-invalid, .input-validation-error")[0]);                   
        if (firstError.length > 0) {
            var tabPane = firstError.closest('.tab-pane');
            if (tabPane.length > 0 && !tabPane.hasClass('show')) {
                var tabId = tabPane.attr('id');
                var tabButton = $(`[data-bs-target="#${tabId}"]`);
                if (tabButton.length > 0) {
                    var tabInstance = bootstrap.Tab.getInstance(tabButton[0]) || new bootstrap.Tab(tabButton[0]);
                    tabInstance.show();

                    setTimeout(function () {
                        firstError.focus();
                        $('html, body').animate({
                            scrollTop: firstError.offset().top - 100             
                        }, 300);
                    }, 300);                      
                }
            } else {
                firstError.focus();
                $('html, body').animate({
                    scrollTop: firstError.offset().top - 100
                }, 300);
            }
        }
        if (typeof toastr !== 'undefined') {
            toastr.warning('Please correct the errors before saving.');
        } else {
            alert('Please correct the errors before saving.');
        }
        return false;                   
    }

    // If form is valid, proceed with AJAX submission
    $.ajax({
        url: '@Url.Action("SaveCompany", "Company")',
        type: 'POST',
        data: form.serialize(),
        success: function(response) {
            if (typeof toastr !== 'undefined') {
                toastr.success('Company saved successfully!');
            }
            window.location.href = '@Url.Action("Index", "Company")';
        },
        error: function(xhr) {
            if (typeof toastr !== 'undefined') {
                toastr.error('An error occurred while saving.');
            }
        }
    });
}