✨ Story 5.2: validation JS contact
This commit is contained in:
217
assets/js/contact-form.js
Normal file
217
assets/js/contact-form.js
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Validation du formulaire de contact
|
||||
* JavaScript vanilla - pas de dépendances
|
||||
*/
|
||||
|
||||
class FormValidator {
|
||||
constructor(formId) {
|
||||
this.form = document.getElementById(formId);
|
||||
if (!this.form) return;
|
||||
|
||||
this.submitBtn = document.getElementById('submit-btn');
|
||||
this.fields = {};
|
||||
this.errors = {};
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.rules = {
|
||||
nom: {
|
||||
required: true,
|
||||
minLength: 2,
|
||||
maxLength: 100,
|
||||
message: 'Veuillez entrer votre nom (2 caractères minimum)'
|
||||
},
|
||||
prenom: {
|
||||
required: true,
|
||||
minLength: 2,
|
||||
maxLength: 100,
|
||||
message: 'Veuillez entrer votre prénom (2 caractères minimum)'
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true,
|
||||
message: 'Veuillez entrer une adresse email valide'
|
||||
},
|
||||
categorie: {
|
||||
required: true,
|
||||
message: 'Veuillez sélectionner une catégorie'
|
||||
},
|
||||
objet: {
|
||||
required: true,
|
||||
minLength: 5,
|
||||
maxLength: 200,
|
||||
message: 'Veuillez entrer un objet (5 caractères minimum)'
|
||||
},
|
||||
message: {
|
||||
required: true,
|
||||
minLength: 20,
|
||||
maxLength: 5000,
|
||||
message: 'Veuillez entrer votre message (20 caractères minimum)'
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys(this.rules).forEach((fieldName) => {
|
||||
this.fields[fieldName] = this.form.querySelector(`[name="${fieldName}"]`);
|
||||
});
|
||||
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
Object.keys(this.fields).forEach((fieldName) => {
|
||||
const field = this.fields[fieldName];
|
||||
if (field) {
|
||||
field.addEventListener('blur', () => this.validateField(fieldName));
|
||||
field.addEventListener('input', () => this.clearError(fieldName));
|
||||
}
|
||||
});
|
||||
|
||||
this.form.addEventListener('submit', (e) => this.handleSubmit(e));
|
||||
|
||||
const messageField = this.fields.message;
|
||||
if (messageField) {
|
||||
messageField.addEventListener('input', () => this.updateCharCount());
|
||||
}
|
||||
}
|
||||
|
||||
validateField(fieldName) {
|
||||
const field = this.fields[fieldName];
|
||||
const rule = this.rules[fieldName];
|
||||
|
||||
if (!field || !rule) return true;
|
||||
|
||||
const value = field.value.trim();
|
||||
let isValid = true;
|
||||
let errorMessage = '';
|
||||
|
||||
if (rule.required && !value) {
|
||||
isValid = false;
|
||||
errorMessage = rule.message;
|
||||
}
|
||||
|
||||
if (isValid && rule.minLength && value.length < rule.minLength) {
|
||||
isValid = false;
|
||||
errorMessage = rule.message;
|
||||
}
|
||||
|
||||
if (isValid && rule.maxLength && value.length > rule.maxLength) {
|
||||
isValid = false;
|
||||
errorMessage = `Maximum ${rule.maxLength} caractères`;
|
||||
}
|
||||
|
||||
if (isValid && rule.email && value) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(value)) {
|
||||
isValid = false;
|
||||
errorMessage = rule.message;
|
||||
}
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
this.clearError(fieldName);
|
||||
} else {
|
||||
this.showError(fieldName, errorMessage);
|
||||
}
|
||||
|
||||
this.errors[fieldName] = !isValid;
|
||||
this.updateSubmitButton();
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
validateAll() {
|
||||
let allValid = true;
|
||||
|
||||
Object.keys(this.rules).forEach((fieldName) => {
|
||||
if (!this.validateField(fieldName)) {
|
||||
allValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
return allValid;
|
||||
}
|
||||
|
||||
showError(fieldName, message) {
|
||||
const field = this.fields[fieldName];
|
||||
const errorEl = this.form.querySelector(`[data-error="${fieldName}"]`);
|
||||
|
||||
if (field) {
|
||||
field.classList.add('input-error');
|
||||
field.setAttribute('aria-invalid', 'true');
|
||||
}
|
||||
|
||||
if (errorEl) {
|
||||
errorEl.textContent = message;
|
||||
errorEl.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
clearError(fieldName) {
|
||||
const field = this.fields[fieldName];
|
||||
const errorEl = this.form.querySelector(`[data-error="${fieldName}"]`);
|
||||
|
||||
if (field) {
|
||||
field.classList.remove('input-error');
|
||||
field.removeAttribute('aria-invalid');
|
||||
}
|
||||
|
||||
if (errorEl) {
|
||||
errorEl.textContent = '';
|
||||
errorEl.classList.add('hidden');
|
||||
}
|
||||
|
||||
this.errors[fieldName] = false;
|
||||
this.updateSubmitButton();
|
||||
}
|
||||
|
||||
updateSubmitButton() {
|
||||
const hasErrors = Object.values(this.errors).some((err) => err);
|
||||
|
||||
if (this.submitBtn) {
|
||||
this.submitBtn.disabled = hasErrors;
|
||||
}
|
||||
}
|
||||
|
||||
updateCharCount() {
|
||||
const messageField = this.fields.message;
|
||||
const countEl = document.getElementById('message-count');
|
||||
|
||||
if (messageField && countEl) {
|
||||
countEl.textContent = messageField.value.length;
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!this.validateAll()) {
|
||||
const firstError = Object.keys(this.errors).find((key) => this.errors[key]);
|
||||
if (firstError && this.fields[firstError]) {
|
||||
this.fields[firstError].focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.form.dispatchEvent(new CustomEvent('validSubmit'));
|
||||
}
|
||||
|
||||
getFormData() {
|
||||
const formData = {};
|
||||
Object.keys(this.fields).forEach((fieldName) => {
|
||||
if (this.fields[fieldName]) {
|
||||
formData[fieldName] = this.fields[fieldName].value.trim();
|
||||
}
|
||||
});
|
||||
const entreprise = this.form.querySelector('[name="entreprise"]');
|
||||
if (entreprise) {
|
||||
formData.entreprise = entreprise.value.trim();
|
||||
}
|
||||
return formData;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.contactFormValidator = new FormValidator('contact-form');
|
||||
});
|
||||
Reference in New Issue
Block a user