问题
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 .= ' <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 .= ' <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