assets_js_controllers_member-unique-email-controller.js

import { Controller } from "@hotwired/stimulus"

/**
 * MemberUniqueEmail Stimulus Controller
 * 
 * Provides real-time email uniqueness validation with AJAX checking and 
 * Bootstrap validation feedback. Ensures email addresses are unique across
 * the system while providing immediate user feedback.
 * 
 * Features:
 * - Real-time email uniqueness validation
 * - AJAX-based server-side checking
 * - Bootstrap validation class integration
 * - Original email comparison for updates
 * - Custom HTML5 validation messages
 * - Visual feedback with is-valid/is-invalid classes
 * - Automatic event listener management
 * 
 * Values:
 * - url: String - API endpoint for email uniqueness checking
 * 
 * Required HTML attributes:
 * - data-original-value: Original email value for comparison during updates
 * 
 * Usage:
 * <input type="email" 
 *        data-controller="member-unique-email"
 *        data-member-unique-email-url-value="/api/check-email"
 *        data-original-value="existing@example.com"
 *        name="email" required>
 */
class MemberUniqueEmail extends Controller {
    static values = { url: String }

    /**
     * Connect controller to DOM
     * Sets up event listeners and removes conflicting attributes
     */
    connect() {
        this.element.removeAttribute('oninput');
        this.element.removeAttribute('oninvalid');
        this.element.addEventListener('change', this.checkEmail.bind(this));
    }

    /**
     * Disconnect controller from DOM
     * Cleans up event listeners
     */
    disconnect(event) {
        this.element.removeEventListener('change', this.checkEmail.bind(this));
    }

    /**
     * Configure fetch options for AJAX requests
     * Sets up headers for JSON API communication
     * 
     * @returns {Object} Fetch options object
     */
    optionsForFetch() {
        return {
            headers: {
                "X-Requested-With": "XMLHttpRequest",
                "Accept": "application/json"
            }
        }
    }

    /**
     * Check email uniqueness via AJAX
     * Validates email against server and updates UI with Bootstrap classes
     * 
     * @param {Event} event - Change event from email input
     */
    checkEmail(event) {
        var email = this.element.value;
        if (email == '') {
            this.element.classList.remove('is-invalid');
            this.element.classList.remove('is-valid');
            this.element.setCustomValidity('');
            return;
        }
        var originalEmail = this.element.dataset.originalValue.toLowerCase();
        if (email.toLowerCase() == originalEmail) {
            this.element.classList.add('is-valid');
            this.element.classList.remove('is-invalid');
            return;
        }
        var checkEmailUrl = this.urlValue + '?nostack=yes&email=' + encodeURIComponent(email);
        fetch(checkEmailUrl, this.optionsForFetch())
            .then(response => response.json())
            .then(data => {
                if (data) {
                    this.element.classList.add('is-invalid');
                    this.element.classList.remove('is-valid');
                    this.element.setCustomValidity('This email address is already taken.');
                } else {
                    this.element.classList.add('is-valid');
                    this.element.classList.remove('is-invalid');
                    this.element.setCustomValidity('');
                }
            });
    }

}
if (!window.Controllers) {
    window.Controllers = {}
}
window.Controllers["member-unique-email"] = MemberUniqueEmail;