Blog Sections Open

Making FormLister Work with AJAX in Evolution CMS 1.4.x and 3.x

A practical AJAX + FormLister pattern that keeps the form in place, returns validation errors as JSON, and preserves uploaded files on failed submission.

One of the nicest upgrades you can make to an Evolution CMS form is to stop reloading the entire page after every validation error. A strong AJAX pattern keeps the form in place, returns validation feedback as JSON, and lets the user correct only the fields that failed.

The core idea is simple: let FormLister work in an API-style mode where it returns only validation results as JSON. The frontend script catches that response, marks the invalid fields, and gives the user another chance without blowing away the whole form.

Why this pattern works well

  • The form does not disappear or reload after every submit attempt.
  • Validation errors can be attached to the right fields through data attributes.
  • Even file inputs can remain intact instead of forcing the user to upload everything again.

Workflow summary

  • The form posts with FormData over AJAX.
  • FormLister validates and returns JSON.
  • The script removes old error state, adds new error messages where needed, and replaces the form with a success block only after valid processing.

This is exactly the kind of pattern worth documenting because it upgrades the user experience without requiring a full frontend framework.

Minimal frontend flow

const form = document.querySelector('.contact-form');

form.addEventListener('submit', async (event) => {
  event.preventDefault();

  const response = await fetch(form.action || window.location.href, {
    method: 'POST',
    body: new FormData(form),
    headers: {
      'X-Requested-With': 'XMLHttpRequest'
    }
  });

  const result = await response.json();

  form.querySelectorAll('.field-error').forEach((node) => node.textContent = '');
  form.querySelectorAll('.is-invalid').forEach((node) => node.classList.remove('is-invalid'));

  if (result.errors) {
    Object.entries(result.errors).forEach(([name, message]) => {
      const input = form.querySelector(`[name="${name}"]`);
      const error = form.querySelector(`[data-error-for="${name}"]`);
      if (input) input.classList.add('is-invalid');
      if (error) error.textContent = message;
    });
    return;
  }

  form.outerHTML = result.success || '
Done.
'; });

The important part is not the exact JavaScript syntax. The important part is keeping the validation contract stable: the backend returns predictable JSON keys, and the frontend knows exactly where to print those errors.

Source: Community article on EvoCMS.ru.

Newer post

Matching Related Articles by TV Values in DocLister

A component-focused note on building related article blocks in DocLister by comparing shared values stored in a TV field.

Older post

Sending FormLister Uploads as Links Instead of Heavy Email Attachments

How to save uploaded files from FormLister and send recipients a download link instead of attaching every file directly to the email.