Custom HTML5 form validation errors only happen after first attempt

做~自己de王妃 提交于 2021-02-08 15:14:52

问题


The below code allows my client to create a custom form with different types of fields and then allows their clients to fill that form in and submit it somewhere. Basically, a custom form builder for Wordpress.

I have successfully replaced the custom behavior for the HTML5 form validation error messages using the below code. However, the custom message I have set for the different types of form fields only appear the 2nd time the form submit is attempted. The first time the submit button is pressed, the default message appears instead.

How can I get the custom messages I've defined to be used the first time as well?

Sorry for the long code, it's a complicated application. In the PHP section, look under the Start Input Wrap section for where I set the custom error messages like so:

onchange="setCustomValidity(\'\')" oninvalid="this.setCustomValidity(\''.$placeholder.' is required.\')"

PHP/HTML:

function sdForm($atts) {
    //Check for a form id variable in the shortcode and, if it's exists, put it into the $formID variable
    $shortcodeAtt = shortcode_atts( array(
        'id' => false,
        ), $atts );
    if ($shortcodeAtt != false) {
        $formID = $shortcodeAtt['id'];

        //Setup this form's settings and variables
        global $post;
        $post = get_post($formID);
        setup_postdata($post);

        //General Variables
        $formTitle = get_the_title();
        $formSlug = $post->post_name;

        //Form Submit Behavior
        $onSubmit = get_field('on_form_submit');
        if ($onSubmit == 'default') {
            //refresh page, display thank you
        } elseif ($onSubmit == 'message') {
            //refresh page, display custom message
            $message = get_field('custom_submission_message');
        } elseif ($onSubmit == 'url') {
            //send user to this page
            $url = get_field('submission_redirect');
        }

        //Form Submit To
        $actionUrl = get_field('form_action_link');

        //Set value of submit button
        if (get_field('submit_value')) {
            $submitValue = get_field('submit_value');
        } else {
            $submitValue = 'Submit';
        }

        //Set ID for form
        if (get_field('form_id')) {
            $formHtmlId = get_field('form_id');
        } else {
            $formHtmlId = $formSlug;
        }

        //Set Classes for form
        if (get_field('form_classes')) {
            $formClasses = get_field('form_classes');
        } else {
            $formClasses = '';
        }

        //Set any messages to display
        $messages = '';
        $confirmMessage = get_field('custom_submission_message');
        if ($_GET['confirm-message']) {
            $messages .= $confirmMessage.'<br />';
        } elseif ($_GET['confirm-submit']) {
            $messages .= 'Thanks for your submission!';
        }

        //Start the HTML output
        $output = '';
        //Do some clearing, just in case
        $output .= '<div style="clear:both;"></div>';
        $output .= '<div class="sdFormWrapper">';
        $output .= '<div class="sdFormMessages">';
        $output .= $messages;
        $output .= '</div>';
        $output .= '<form name="'.$formSlug.'" id="'.$formHtmlId.'" class="'.$formClasses.' sd_form" method="post" ';
        if (isset($actionUrl)) {
            $output .= 'action="'.$actionUrl.'" ';
        }
        $output .= '>';

        //We add a hidden field to identify which form is being processed after submit
        $output .= '<input type="hidden" name="formID" value="'.$formID.'" />';

        //This loops through each added field and displays each one
        if (have_rows('input_type')) {
            while (have_rows('input_type')) { the_row();

            //We're putting a uniform wrap around each input element for styling
            if (get_sub_field('fill_row') == true) {
                $fullWidth = 'fullWidth';
            } else {
                $fullWidth = '';
            }
            if (get_row_layout() == 'section_header') {
                $output .= '<div class="sectionHeader">';
                $output .= get_sub_field('header_text');
                $output .= '</div>';
            } else {



            //We turn the field label into a slug with no spaces or special characters
            $fieldSlug = sanitize_title(get_sub_field('label'));

            //Check if this field is required
            if (get_sub_field('required') == true) {
                    $required = 'required';
            } else {
                    $required = '';
            }
            //Check for custom name
            if (get_sub_field('input_name')) {
                $name = get_sub_field('input_name');
            } else {
                $name = $fieldSlug;
            }
            //Check for custom html id
            if (get_sub_field('input_id')) {
                $htmlId = get_sub_field('input_id');
            } else {
                $htmlId = $name;
            }
            //Check for custom html classes
            if (get_sub_field('input_class')) {
                $htmlClass = get_sub_field('input_class').' sdForm-input';
            } else {
                $htmlClass = 'sdForm-input';
            }
            //Check for icons
            if (get_sub_field('icon')) {
                    $icon = get_sub_field('icon');
                } else {
                    $icon = '';
                }
            //Generate Placeholder  (this is the field label)
            $placeholder = get_sub_field('label');

            //Start input wrap
            $output .= '<div title="'.$placeholder.'" class="sdForm-inputWrap '.$fullWidth.'">';

            //Error message for field
            //$output .= '<div class="inputError">'.$placeholder.' is required!</div>'; 
                $output .= $icon;
                if (get_row_layout() == 'text') {
                    $output .= '<input type="text" name="'.$name.'" id="'.$htmlId.'" class="'.$htmlClass.'" placeholder="'.$placeholder.'" title="'.$placeholder.'" '.$required.' onchange="setCustomValidity(\'\')" oninvalid="this.setCustomValidity(\''.$placeholder.' is required.\')"  />';
                } elseif (get_row_layout() == 'textBox') {
                    $output .= '<textarea rows="4" id="'.$htmlId.'" class="'.$htmlClass.'" placeholder="'.$placeholder.'" title="'.$placeholder.'" '.$required.' onchange="setCustomValidity(\'\')" oninvalid="this.setCustomValidity(\''.$placeholder.' is required.\')"></textarea>';
                } elseif (get_row_layout() == 'email') {
                    $output .= '<input type="email" name="'.$name.'" id="'.$htmlId.'" class="'.$htmlClass.'" placeholder="'.$placeholder.'" title="'.$placeholder.'" '.$required.' onchange="setCustomValidity(\'\')" oninvalid="this.setCustomValidity(\''.$placeholder.' is required and must be valid.\')"/>';
                } elseif (get_row_layout() == 'phone') {
                    $output .= '<input type="tel" name="'.$name.'" id="'.$htmlId.'" class="'.$htmlClass.'" placeholder="'.$placeholder.'" title="'.$placeholder.'" '.$required.' onchange="setCustomValidity(\'\')" oninvalid="this.setCustomValidity(\''.$placeholder.' is required.\')"/>';
                } elseif (get_row_layout() == 'url') {
                    $output .= '<input type="url" name="'.$name.'" id="'.$htmlId.'" class="'.$htmlClass.'" placeholder="'.$placeholder.'" title="'.$placeholder.'" '.$required.' onchange="setCustomValidity(\'\')" oninvalid="this.setCustomValidity(\''.$placeholder.' is required.\')"/>';
                } elseif (get_row_layout() == 'checkboxes') {
                    if (have_rows('checkbox_selections')) {
                        if ($placeholder != '') {
                            $output .= '<label for="'.$htmlId.'">'.$placeholder.'</label><br />';
                        }
                        while(have_rows('checkbox_selections')) { the_row();
                            $selection = get_sub_field('checkbox_selection');
                            $output .= '<input type="checkbox" name="'.$name.'" value="'.$selection.'" id="'.$htmlId.'" class="'.$htmlClass.'" title="'.$placeholder.'" '.$required.' onchange="setCustomValidity(\'\')" oninvalid="this.setCustomValidity(\''.$placeholder.' is required.\')"/>';
                            $output .= '&nbsp;&nbsp;<label for="'.$htmlId.'">'.$selection.'</label><br />';
                        }
                    }
                } elseif (get_row_layout() == 'radios') {
                    if (have_rows('radio_selections')) {
                        if ($placeholder != '') {
                            $output .= '<label for="'.$htmlId.'">'.$placeholder.'</label><br />';
                        }
                        while(have_rows('radio_selections')) { the_row();
                            $selection = get_sub_field('radio_selection');
                            $output .= '<input type="radio" name="'.$name.'" value="'.$selection.'" id="'.$htmlId.'" class="'.$htmlClass.'" title="'.$placeholder.'" '.$required.' onchange="setCustomValidity(\'\')" oninvalid="this.setCustomValidity(\''.$placeholder.' is required.\')"/>';
                            $output .= '&nbsp;&nbsp;<label for="'.$htmlId.'">'.$selection.'</label><br />';
                        }
                    }
                } elseif (get_row_layout() == 'select') {
                    if (get_sub_field('show_label', true)) {
                        $output .= '<span class="dropdownLabel">'.$placeholder.': </span>';
                        $showLabel = 'showLabel';
                    } else {
                            $showLabel = '';
                    }
                    $optionSlug = sanitize_title($selection);
                    if (have_rows('dropdown_selections')) {

                        $output .= '<select name="'.$name.'" id="'.$htmlId.'" class="'.$htmlClass.' '.$showLabel.'" title="'.$placeholder.'" '.$required.' onchange="setCustomValidity(\'\')" oninvalid="this.setCustomValidity(\''.$placeholder.' is required.\')">';                  
                        $output .= '<option selected="select" disabled>';
                        if ($showLabel != 'showLabel') {
                            $output .= $placeholder;
                        }
                        $output .= '</option>';
                        while(have_rows('dropdown_selections')) { the_row();
                            $selection = get_sub_field('dropdown_selection');
                            $optionSlug = sanitize_title($selection);
                            $output .= '<option value="'.$optionSlug.'">'.$selection.'</option>';                           
                        }
                        $output .= '</select>';
                    }
                } 
            $output .= '<div style="clear:both;"></div>';
            $output .= '</div>'; //.sdForm-inputWrap
            } //end else (if not a message header)
            }//endwhile

        }

        $output .= '<input type="submit" value="'.$submitValue.'" />';

        $output .= '</form><div style="clear: both;"></div></div>';

        wp_reset_postdata();

    } else { //There is no ID set, so we can't show any form
        //ERROR!! No form ID specified
    }
    echo $output;
}

add_shortcode('sdForm', 'sdForm');

JS:

 (function($) {
     $(document).ready(function() {
         function sd_replaceValidationUI(form) {
             // Suppress the default bubbles
             form.addEventListener("invalid", function(event) {
                 event.preventDefault();
             }, true);

             // Support Safari, iOS Safari, and the Android browser—each of which do not prevent
             // form submissions by default
             form.addEventListener("submit", function(event) {
                 if (!this.checkValidity()) {
                     event.preventDefault();
                 }
             });

             var submitButton = form.querySelector("button:not([type=button]), input[type=submit]");
             submitButton.addEventListener("click", function(event) {
                 var invalidFields = form.querySelectorAll(":invalid"),
                     errorMessages = form.querySelectorAll(".error-message"),
                     parent;

                 // Remove any existing messages
                 for (var i = 0; i < errorMessages.length; i++) {
                     errorMessages[i].parentNode.removeChild(errorMessages[i]);
                 }

                 for (var i = 0; i < invalidFields.length; i++) {
                     parent = invalidFields[i].parentNode;
                     parent.insertAdjacentHTML("beforeend", "<div class='error-message'>" +
                         invalidFields[i].validationMessage +
                         "</div>");
                 }

                 // If there are errors, give focus to the first invalid field
                 if (invalidFields.length > 0) {
                     invalidFields[0].focus();
                 }
             });
         }

         // Replace the validation UI for all forms
         var forms = document.querySelectorAll("form");
         for (var i = 0; i < forms.length; i++) {
             sd_replaceValidationUI(forms[i]);
         }


         //Changes the text of the dropdown to #666 when a selection is made
         $('.sdForm-inputWrap select').change(function() {
             $(this).css('color', '#666');
         });

     })
 })(jQuery);

回答1:


I think your problem is you're setting custom validity oninvalid. This works on the default UI but not when you want to customize it.

I tried recreating your code. On first run the invalidFields loop is getting the default invalid error messages. After this the setCustomValidity is then invoked, hence you get the custom error messages on the second run.

To fix this, you must loop through all fields you want to set custom validity and invoke setCustomValidity prior to form submission.

One way is to make use of data attributes in the HTML code. Add the attributes like so for each field:

<input type="text" data-ErrorMessage="Your Custom Error Message" />

And then add this to the existing js:

for (var i=0; i<fields.length; i++){
    var message = $(fields[i]).attr("data-ErrorMessage");
    $(fields[i]).get(0).setCustomValidity(message);
}


来源:https://stackoverflow.com/questions/34259669/custom-html5-form-validation-errors-only-happen-after-first-attempt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!