Email

Phone

+39 02 55014101

Sede Italiana

Via G. Donizetti, 4
20122 Milano IT

Gravity Forms Ajax Better Guide

<script> (function() // DOM elements const form = document.getElementById('gravityAjaxForm'); const fullNameInput = document.getElementById('fullName'); const emailInput = document.getElementById('emailAddress'); const messageInput = document.getElementById('messageContent'); const submitBtn = document.getElementById('submitBtn'); const btnTextSpan = document.getElementById('btnText'); const btnSpinner = document.getElementById('btnSpinner'); // AJAX status panel elements const statusPanel = document.getElementById('ajaxStatusPanel'); const statusIconSpan = document.getElementById('statusIcon'); const statusMessageSpan = document.getElementById('statusMessage'); // Error hint elements const nameErrorDiv = document.getElementById('nameError'); const emailErrorDiv = document.getElementById('emailError'); const msgErrorDiv = document.getElementById('msgError'); // Field wrappers to apply error class styling const nameWrapper = document.getElementById('field-name-wrapper'); const emailWrapper = document.getElementById('field-email-wrapper'); const msgWrapper = document.getElementById('field-msg-wrapper'); // Helper: clear all inline field errors function clearFieldErrors() // remove custom error border class from inputs fullNameInput.classList.remove('field-error'); emailInput.classList.remove('field-error'); messageInput.classList.remove('field-error'); // hide error messages nameErrorDiv.style.display = 'none'; emailErrorDiv.style.display = 'none'; msgErrorDiv.style.display = 'none'; // Helper: display field-specific error function showFieldError(fieldType, message) if (fieldType === 'name') 'Please enter your full name'; nameErrorDiv.style.display = 'block'; else if (fieldType === 'email') 'Valid email is required'; emailErrorDiv.style.display = 'block'; else if (fieldType === 'message') // Reset status panel to neutral (or hide) function setStatusPanel(type, message, customIcon = null) // remove all previous status classes statusPanel.classList.remove('status-success', 'status-error', 'status-info'); if (type === 'success') statusPanel.classList.add('status-success'); statusIconSpan.innerHTML = customIcon else if (type === 'error') statusPanel.classList.add('status-error'); statusIconSpan.innerHTML = customIcon else if (type === 'info') 'ℹ️'; else if (type === 'loading') statusPanel.classList.add('status-info'); statusIconSpan.innerHTML = '⏳'; else '📋'; statusMessageSpan.innerHTML = message; statusPanel.classList.remove('hidden-status'); function hideStatusPanel() statusPanel.classList.add('hidden-status'); // Simulate AJAX request (POST to mock endpoint) — Gravity Forms style async async function submitFormViaAjax(formDataObj) // Simulate network delay (typical Gravity Forms AJAX ~ 600-1200ms) const delay = 800 + Math.random() * 400; // between 800ms and 1200ms realistic // MOCK endpoint: we just simulate server-side validation and response. // In real scenario this would be a REST endpoint like /gf-ajax/submit return new Promise((resolve, reject) => setTimeout(() => // Additional "server-side" validation: check if email domain contains "test" as a special mock error? const fullName, email, message, inquiryType = formDataObj; // Simulate conditional server error: if email ends with "fail@example.com" produce server error if (email.toLowerCase() === 'fail@example.com') reject( type: 'server', message: 'Server could not process request: Email domain blocked (simulated).' ); return; // Simulate successful submission for all valid inputs // For extra realism, if name contains "error" we simulate a server-side validation issue if (fullName.toLowerCase().includes('servererror')) reject( type: 'server', message: 'Server validation error: name contains restricted keyword. Please modify.' ); return; // Otherwise success — return submission data resolve( success: true, message: `✨ Success! Your inquiry ($inquiryType) has been sent. We'll reply to $email within 24 hours.`, submittedAt: new Date().toISOString() ); , delay); ); // Client-side validation (same as typical Gravity Forms built-in validation) function validateClientSide() clearFieldErrors(); let isValid = true; const nameValue = fullNameInput.value.trim(); if (nameValue === '') showFieldError('name', 'Full name is required.'); isValid = false; else if (nameValue.length < 2) showFieldError('name', 'Name must be at least 2 characters.'); isValid = false; const emailValue = emailInput.value.trim(); const emailRegex = /^[^\s@]+@([^\s@]+\.)+[^\s@]+$/; if (emailValue === '') showFieldError('email', 'Email address is required.'); isValid = false; else if (!emailRegex.test(emailValue)) showFieldError('email', 'Please enter a valid email address (e.g., name@domain.com).'); isValid = false; const messageValue = messageInput.value.trim(); if (messageValue === '') showFieldError('message', 'Message cannot be blank.'); isValid = false; else if (messageValue.length < 5) showFieldError('message', 'Message must be at least 5 characters.'); isValid = false; return isValid; // Helper to gather form data object function getFormDataObject() return fullName: fullNameInput.value.trim(), email: emailInput.value.trim(), message: messageInput.value.trim(), inquiryType: document.getElementById('inquiryType').value ; // Set UI loading state function setLoadingState(isLoading) if (isLoading) submitBtn.disabled = true; btnTextSpan.textContent = 'Submitting...'; btnSpinner.style.display = 'inline-block'; // show loading status panel setStatusPanel('loading', 'Processing request asynchronously — please wait...', '⏳'); else submitBtn.disabled = false; btnTextSpan.textContent = 'Submit form'; btnSpinner.style.display = 'none'; // Handle AJAX submission (main event) async function handleFormSubmit(event) event.preventDefault(); // 1. Reset any previous dynamic status but keep panel visible for loading clearFieldErrors(); // 2. Client-side validation (Gravity Forms style) const clientValid = validateClientSide(); if (!clientValid) // display validation error in status panel as well setStatusPanel('error', 'Please fix the highlighted errors before submitting.', '🔍'); // scroll gently to first error? optional: but we show error hints return; // 3. If valid, proceed with AJAX const formData = getFormDataObject(); // set loading UI setLoadingState(true); try // Simulate AJAX request to backend (Gravity Forms like endpoint) const response = await submitFormViaAjax(formData); // success! setLoadingState(false); // show success message with clear Gravity style setStatusPanel('success', response.message, '🎉'); // Optionally reset form fields after successful submission? (Gravity Forms often keeps or resets? // For better UX we clear but we can optionally reset, typical scenario: optional reset) // Uncomment next lines if you prefer to reset after success (like fresh form) fullNameInput.value = ''; emailInput.value = ''; messageInput.value = ''; document.getElementById('inquiryType').value = 'general'; clearFieldErrors(); // after reset any field errors removed // Also remove any lingering highlights fullNameInput.classList.remove('field-error'); emailInput.classList.remove('field-error'); messageInput.classList.remove('field-error'); // Additional success detail: auto-hide status after 6 seconds? but remains visible, user can dismiss? we provide small autohide after 7 seconds but keep setTimeout(() => // only hide if not hover? but we can make status info less intrusive after long time, but we keep visible but change to subtle info if (statusPanel.classList.contains('status-success')) // set to subtle message but not hidden completely, just update to informative statusMessageSpan.innerHTML = response.message + ' — You can submit another entry.'; , 5000); catch (err) setLoadingState(false); let errorMsg = 'Something went wrong with AJAX request.'; if (err && typeof err === 'object') if (err.type === 'server') errorMsg = err.message; else if (err.message) errorMsg = err.message; else errorMsg = 'Network or server error. Please try again later.'; else if (typeof err === 'string') errorMsg = err; setStatusPanel('error', `Submission failed: $errorMsg`, '❌'); // Also if there's a server side specific field mapping we could highlight, but generic error is good. // Simulated field error for server error if message relates to name/email if (errorMsg.toLowerCase().includes('email domain blocked')) showFieldError('email', 'Server rejection: email domain is not allowed.'); else if (errorMsg.toLowerCase().includes('restricted keyword')) showFieldError('name', 'Server flagged name: please use a different name.'); // attach event listener to form form.addEventListener('submit', handleFormSubmit); // Optional: real-time clear field error when user types (enhances UX) function clearSpecificFieldErrorOnInput(field, errorDiv, inputElement) field.addEventListener('input', function() if (errorDiv.style.display === 'block') errorDiv.style.display = 'none'; inputElement.classList.remove('field-error'); // also if status panel shows old error, we don't auto-clear main status, just field errors // but better to reset general status if field correction happens? keep as is ); clearSpecificFieldErrorOnInput(fullNameInput, nameErrorDiv, fullNameInput); clearSpecificFieldErrorOnInput(emailInput, emailErrorDiv, emailInput); clearSpecificFieldErrorOnInput(messageInput, msgErrorDiv, messageInput); // Additionally, when clicking into fields, remove generic error status panel after a small delay? optional. // Makes experience polished. const clearStatusOnFocus = () => // If status panel shows error but user starts typing, we could optionally change status to info. if (statusPanel.classList.contains('status-error')) // small delay to not flicker setTimeout(() => if (statusPanel.classList.contains('status-error')) setStatusPanel('info', 'Continue filling the form — submit again.', '✏️'); , 200); ; fullNameInput.addEventListener('focus', clearStatusOnFocus); emailInput.addEventListener('focus', clearStatusOnFocus); messageInput.addEventListener('focus', clearStatusOnFocus); // Initial status: show info about AJAX (but hidden initially, better to show a hint) // Show a welcome message but not intrusive, just to demonstrate AJAX ready. setTimeout(() => setStatusPanel('info', 'Gravity Forms AJAX mode active — form will submit without reloading the page.', '⚡'); // auto-hide after 4 seconds? keep subtle, but we can hide after 5 sec to keep UI clean setTimeout(() => if (statusPanel && !statusPanel.classList.contains('hidden-status') && !submitBtn.disabled) hideStatusPanel(); , 4500); , 300); )(); </script> </body> </html>

.status-icon font-size: 1.3rem;

/* subtle field error highlight */ .field-error border-color: #c73e2f !important; background-color: #fff8f7 !important; gravity forms ajax

/* simple footer */ .gf-footer background: #f7fafc; padding: 1rem 2rem; font-size: 0.75rem; text-align: center; color: #4a627a; border-top: 1px solid #e2edf7; &lt;script&gt; (function() // DOM elements const form =