Sprawdź jak walidować formularze w czystym JS!

Spis treści

  1. Wprowadzenie
  2. Walidowanie formularzy
    1. Baza pod przykłady
    2. Customowe wiadomości dla walidacji standardowej
    3. Customowy sposób prezentacji rezultatów walidacji
    4. Klikalny przykład na Github Pages
    5. Pełny kod przykładu na Github
  3. Podsumowanie

Wprowadzenie

Walidowanie formularzy nie zawsze jest prostym zadaniem – najczęściej wyłączamy domyślną walidację i piszemy bardzo customowy kod. Okazuje się jednak, że JS ma wbudowane Constraint Validation API a także umożliwia prostą zmianę domyślnych tekstów które pokazywane są użytkownikowi podczas domyślnej walidacji formularza.

Walidowanie formularzy

Baza pod przykłady

Bazą będzie formularz HTML zawierający pola różnego typu:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<form>
<div class="form-group">
<label for="name">
Name
</label>
<input id="name" name="name" type="text" minlength="2" maxlength="10" required>
<div class="form-group__error"></div>
</div>
<!-- Inne pola -->
</form>
<form> <div class="form-group"> <label for="name"> Name </label> <input id="name" name="name" type="text" minlength="2" maxlength="10" required> <div class="form-group__error"></div> </div> <!-- Inne pola --> </form>
<form>
  <div class="form-group">
    <label for="name">
      Name
    </label>
    <input id="name" name="name" type="text" minlength="2" maxlength="10" required>
    <div class="form-group__error"></div>
  </div>
  <!-- Inne pola -->
</form>

Potrzebny nam będzie również checkbox za pomocą którego będziemy wybierać, czy chcemy użyć natywnej walidacji HTML czy też dodać atrybut

novalidate
novalidate do formularza i zawsze wywoływać funkcję submit:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<label for="nativeValidation">
Native validation?
<input type="checkbox" id="nativeValidation" checked />
</label>
<label for="nativeValidation"> Native validation? <input type="checkbox" id="nativeValidation" checked /> </label>
<label for="nativeValidation">
  Native validation?
  <input type="checkbox" id="nativeValidation" checked />
</label>

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const nativeValidationCheckbox = document
.querySelector('#nativeValidation');
nativeValidationCheckbox
.addEventListener('change', () => {
form.toggleAttribute('novalidate', !nativeValidationCheckbox.checked);
});
const nativeValidationCheckbox = document .querySelector('#nativeValidation'); nativeValidationCheckbox .addEventListener('change', () => { form.toggleAttribute('novalidate', !nativeValidationCheckbox.checked); });
const nativeValidationCheckbox = document
  .querySelector('#nativeValidation');
nativeValidationCheckbox
  .addEventListener('change', () => {
    form.toggleAttribute('novalidate', !nativeValidationCheckbox.checked);
  });

Customowe wiadomości dla walidacji standardowej

Jeśli odpowiada nam aktualny sposób walidacji który HTML ma wbudowany, możemy tylko zaktualizować wiadomości pokazywane użytkownikowi.

Zmiany tej możemy dokonać dzięki funkcji setCustomValidity.

Customową wiadomość ustawiać możemy na przykład w momencie, gdy użytkownik wpisuje dane w polu:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const validateInput = input => {
const customValidity = getCustomValidity(input);
input.setCustomValidity(customValidity);
}
form.addEventListener('input', e => {
const input = e.target;
input
.parentElement
.querySelector('.form-group__error').innerHTML = '';
validateInput(input);
});
const validateInput = input => { const customValidity = getCustomValidity(input); input.setCustomValidity(customValidity); } form.addEventListener('input', e => { const input = e.target; input .parentElement .querySelector('.form-group__error').innerHTML = ''; validateInput(input); });
const validateInput = input => {
  const customValidity = getCustomValidity(input);
  input.setCustomValidity(customValidity);
}
    
form.addEventListener('input', e => {
  const input = e.target;
  input
    .parentElement
    .querySelector('.form-group__error').innerHTML = '';
  validateInput(input);
});

W jaki sposób natomiast stworzymy wiadomości? Bazując na interfejsie ValidityState, dzięki któremu każdy input zawiera informację o błędach walidacji:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const getCustomValidity = input => {
const validity = input.validity;
const name = input.name.charAt(0).toUpperCase() + input.name.slice(1);
if (validity.valueMissing) {
return `${name} is needed for account`;
}
if (validity.tooShort) {
return `Please provide at least ${input.minLength} characters for ${name}`;
}
if (validity.tooLong) {
return `Please provide at most ${input.maxLength} characters for ${name}`;
}
if (validity.rangeUnderflow) {
return `Please provide value which is at least ${input.min} for ${name}`;
}
if (validity.rangeOverflow) {
return `Please provide value which is at most ${input.max} for ${name}`;
}
if (validity.typeMismatch) {
if (input.type === 'email') {
return `Please provide a valid email - copy it from your mailbox`;
}
if (input.type === 'url') {
`Please provide a valid url - copy it from browser address bar`;
}
}
return '';
}
const getCustomValidity = input => { const validity = input.validity; const name = input.name.charAt(0).toUpperCase() + input.name.slice(1); if (validity.valueMissing) { return `${name} is needed for account`; } if (validity.tooShort) { return `Please provide at least ${input.minLength} characters for ${name}`; } if (validity.tooLong) { return `Please provide at most ${input.maxLength} characters for ${name}`; } if (validity.rangeUnderflow) { return `Please provide value which is at least ${input.min} for ${name}`; } if (validity.rangeOverflow) { return `Please provide value which is at most ${input.max} for ${name}`; } if (validity.typeMismatch) { if (input.type === 'email') { return `Please provide a valid email - copy it from your mailbox`; } if (input.type === 'url') { `Please provide a valid url - copy it from browser address bar`; } } return ''; }
const getCustomValidity = input => {
  const validity = input.validity;
  const name = input.name.charAt(0).toUpperCase() + input.name.slice(1);
  if (validity.valueMissing) {
    return `${name} is needed for account`;
  }
  if (validity.tooShort) {
    return `Please provide at least ${input.minLength} characters for ${name}`;
  }
  if (validity.tooLong) {
    return `Please provide at most ${input.maxLength} characters for ${name}`;
  }
  if (validity.rangeUnderflow) {
    return `Please provide value which is at least ${input.min} for ${name}`;
  }
  if (validity.rangeOverflow) {
    return `Please provide value which is at most ${input.max} for ${name}`;
  }
  if (validity.typeMismatch) {
    if (input.type === 'email') {
      return `Please provide a valid email - copy it from your mailbox`;
    }
    if (input.type === 'url') {
      `Please provide a valid url - copy it from browser address bar`;
    }
 }
 return '';
}

Dzięki temu, przykładowo jeśli podamy tylko jeden znak gdy wymagane są co najmniej dwa, pojawi się zdefiniowana przez nas wiadomość:

Customowy sposób prezentacji rezultatów walidacji

Co jednak, jeśli nie odpowiada nam natywna walidacja? Możemy wyłączyć ją dodając atrybut

novalidate
novalidate na formularzu. W takiej sytuacji walidować musimy ręcznie, np. w reakcji na wysłanie formularza. Do walidacji możemy reużyć sposobu z poprzedniego paragrafu bazującego na
validity
validity:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
form.addEventListener('submit', e => {
e.preventDefault();
const inputs = Array
.from(e.currentTarget)
.filter(el => el.id); // to remove button
for (const input of inputs) {
const customValidity = getCustomValidity(input);
if (customValidity) {
input
.parentElement
.querySelector('.form-group__error')
.innerHTML = customValidity;
return;
}
}
const values = inputs
.reduce((acc, current) => ({
...acc,
[current.id]: current.value,
}), {});
e.currentTarget.reset();
alert(JSON.stringify(values));
});
form.addEventListener('submit', e => { e.preventDefault(); const inputs = Array .from(e.currentTarget) .filter(el => el.id); // to remove button for (const input of inputs) { const customValidity = getCustomValidity(input); if (customValidity) { input .parentElement .querySelector('.form-group__error') .innerHTML = customValidity; return; } } const values = inputs .reduce((acc, current) => ({ ...acc, [current.id]: current.value, }), {}); e.currentTarget.reset(); alert(JSON.stringify(values)); });
form.addEventListener('submit', e => {
  e.preventDefault();

  const inputs = Array
    .from(e.currentTarget)
    .filter(el => el.id); // to remove button

  for (const input of inputs) {
    const customValidity = getCustomValidity(input);
    if (customValidity) {
      input
        .parentElement
        .querySelector('.form-group__error')
        .innerHTML = customValidity;
      return;
    }
  }

  const values = inputs
    .reduce((acc, current) => ({
      ...acc,
      [current.id]: current.value,
   }), {});
  e.currentTarget.reset();
  alert(JSON.stringify(values));
});

W funkcji przechodzimy przez wszystkie inputy, jeżeli dla któregoś mamy wiadomość o błędzie walidacji wtedy wyświetlamy ją i wychodzimy z funkcji:

A jeśli błędów nie ma, wtedy za pomocą funkcji

reduce
reduce transformujemy dane w formularzu do obiektu i wyświetlamy je alertem.

Klikalny przykład na Github Pages

Klikalny przykład znajduje się pod adresem:

https://radek-anuszewski.github.io/custom-validation-demo/

Pełny kod przykładu na Github

Pełen kod przykładu znajduje się pod adresem:

https://github.com/radek-anuszewski/custom-validation-demo

Podsumowanie

Walidując formularze nie zawsze musimy polegać na frameworkach czy bibliotekach – wbudowane w JS mechanizmy potrafią całkiem sporo i warto je znać oraz stosować.

Jeden komentarz do “Sprawdź jak walidować formularze w czystym JS!”

Możliwość komentowania została wyłączona.