#195 - Custom Input Validation v0.1

Add real-time form validation with custom error messages.

Demo ansehen

<!-- 💙 MEMBERSCRIPT #195 v0.1 💙 - CUSTOM INPUT VALIDATION WITH ERROR MESSAGES -->
<!--
  A flexible validation system for form inputs that supports international formats
  for postal codes, phone numbers, email addresses, and custom regex patterns.
  
  CUSTOMIZATION GUIDE:
  ====================
  All customizable sections are marked with "MODIFY:" comments below.
  Search for "MODIFY:" to find all areas you can customize.
  
  Key Customization Areas:
  1. VALIDATION PATTERNS (lines ~20-60) - Change regex patterns for different countries
  2. ERROR MESSAGES (lines ~65-75) - Customize error messages in any language
  3. OPTIONS (lines ~80-85) - Toggle validation features on/off
-->
<script>
(function() {
  'use strict';
  
  // ============================================================================
  // MODIFY: SELECTORS - Change these if you use different data-ms-code attributes
  // ============================================================================
  const CONFIG = {
    SELECTORS: {
      form: '[data-ms-code="validation-form"]',
      inputPrefix: '[data-ms-code^="validation-input-"]',
      errorPrefix: '[data-ms-code^="validation-error-"]'
    },
    
    // ============================================================================
    // MODIFY: VALIDATION PATTERNS - Customize for your country/region
    // ============================================================================
    // Replace these patterns with formats for your country or use 'regex' type
    // for custom patterns. Examples for different countries are provided below.
    PATTERNS: {
      // POSTAL CODE PATTERNS (choose one or use 'regex' for custom)
      // US ZIP: 12345 or 12345-6789
      zip: /^\d{5}(-\d{4})?$/,
      
      // UK Postcode: SW1A 1AA, M1 1AA, B33 8TH
      // Uncomment to use UK format instead:
      // zip: /^[A-Z]{1,2}\d{1,2}[A-Z]?\s?\d[A-Z]{2}$/i,
      
      // Canadian Postal Code: A1A 1A1
      // Uncomment to use Canadian format instead:
      // zip: /^[A-Z]\d[A-Z]\s?\d[A-Z]\d$/i,
      
      // Australian Postcode: 2000-9999
      // Uncomment to use Australian format instead:
      // zip: /^\d{4}$/,
      
      // German Postcode: 12345
      // Uncomment to use German format instead:
      // zip: /^\d{5}$/,
      
      // Flexible international postal code (allows letters, numbers, spaces, hyphens)
      // Uncomment to use flexible format:
      // zip: /^[A-Z0-9\s\-]{3,10}$/i,
      
      // PHONE NUMBER PATTERNS
      // Flexible international phone (allows digits, spaces, hyphens, parentheses, plus, dots)
      phone: /^[\d\s\-\(\)\+\.]+$/,
      
      // US Phone: (123) 456-7890 or 123-456-7890
      // Uncomment to use US format instead:
      // phone: /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/,
      
      // International with country code: +1 234 567 8900, +44 20 1234 5678
      // Uncomment to use international format:
      // phone: /^[\+]?[1-9][\d]{0,15}$/,
      
      // EMAIL PATTERN (works internationally)
      email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    },
    
    // ============================================================================
    // MODIFY: ERROR MESSAGES - Customize messages in your language
    // ============================================================================
    // Change these messages to match your language and validation rules
    MESSAGES: {
      // Postal code messages (update example to match your pattern)
      zip: 'Please enter a valid postal code',
      // Examples for different countries:
      // zip: 'Please enter a valid UK postcode (e.g., SW1A 1AA)',
      // zip: 'Please enter a valid Canadian postal code (e.g., A1A 1A1)',
      // zip: 'Bitte geben Sie eine gültige Postleitzahl ein', // German
      // zip: 'Por favor ingrese un código postal válido', // Spanish
      
      // Phone number messages
      phone: 'Please enter a valid phone number',
      // Examples:
      // phone: 'Please enter a valid phone number (e.g., +1 234 567 8900)',
      // phone: 'Bitte geben Sie eine gültige Telefonnummer ein', // German
      
      // Email messages
      email: 'Please enter a valid email address',
      
      // Generic messages
      regex: 'Please enter a valid value',
      required: 'This field is required',
      default: 'Please enter a valid value'
    },
    
    // ============================================================================
    // MODIFY: OPTIONS - Toggle validation features on/off
    // ============================================================================
    OPTIONS: {
      realTimeValidation: true,  // Show errors as user types
      validateOnBlur: true,  // Validate when user leaves the field
      preventSubmit: true  // Prevent form submission if validation fails
    }
  };
  
  let form = null;
  let validationRules = [];
  
  // TIMING - Adjust timeout values if needed (in milliseconds)
  function waitFor(condition, timeout = 5000) {
    return new Promise((resolve) => {
      if (condition()) return resolve();
      const interval = setInterval(() => {
        if (condition()) {
          clearInterval(interval);
          resolve();
        }
      }, 100);
      setTimeout(() => {
        clearInterval(interval);
        resolve();
      }, timeout);
    });
  }
  
  async function init() {
    await waitFor(() => document.querySelector(CONFIG.SELECTORS.form));
    
    form = document.querySelector(CONFIG.SELECTORS.form);
    if (!form) {
      console.warn('MemberScript #195: Form not found. Add data-ms-code="validation-form" to your form element.');
      return;
    }
    
    // Find all inputs with validation attributes
    const inputs = form.querySelectorAll(CONFIG.SELECTORS.inputPrefix);
    
    if (inputs.length === 0) {
      console.warn('MemberScript #195: No validation inputs found. Add data-ms-code="validation-input-[name]" to your inputs.');
      return;
    }
    
    // Build validation rules for each input
    inputs.forEach(input => {
      const inputCode = input.getAttribute('data-ms-code');
      const fieldName = inputCode.replace('validation-input-', '');
      const validationType = input.getAttribute('data-validation-type');
      const errorElement = form.querySelector(`[data-ms-code="validation-error-${fieldName}"]`);
      
      if (!validationType) {
        console.warn(`MemberScript #195: Input "${fieldName}" missing data-validation-type attribute.`);
        return;
      }
      
      if (!errorElement) {
        console.warn(`MemberScript #195: Error element not found for "${fieldName}". Add data-ms-code="validation-error-${fieldName}".`);
        return;
      }
      
      // Hide error message initially
      errorElement.style.display = 'none';
      
      // Build validation rule
      const rule = {
        input: input,
        fieldName: fieldName,
        type: validationType,
        errorElement: errorElement,
        pattern: null,
        message: null,
        required: input.hasAttribute('required') || input.getAttribute('data-validation-required') === 'true'
      };
      
      // Set up validation based on type
      if (validationType === 'regex') {
        // MODIFY: Custom regex validation - use data-validation-pattern attribute
        // Example: data-validation-pattern="^[A-Z0-9]{5}$" for 5 alphanumeric characters
        const customPattern = input.getAttribute('data-validation-pattern');
        const customMessage = input.getAttribute('data-validation-message');
        
        if (!customPattern) {
          console.warn(`MemberScript #195: Regex validation requires data-validation-pattern attribute for "${fieldName}".`);
          return;
        }
        
        try {
          rule.pattern = new RegExp(customPattern);
          rule.message = customMessage || CONFIG.MESSAGES.regex;
        } catch (e) {
          console.error(`MemberScript #195: Invalid regex pattern for "${fieldName}":`, e);
          return;
        }
      } else if (CONFIG.PATTERNS[validationType]) {
        // Use predefined pattern from CONFIG.PATTERNS
        rule.pattern = CONFIG.PATTERNS[validationType];
        rule.message = CONFIG.MESSAGES[validationType];
        
        // MODIFY: Override message per field using data-validation-message attribute
        // Example: <input data-validation-message="Custom error message" ...>
        const fieldMessage = input.getAttribute('data-validation-message');
        if (fieldMessage) {
          rule.message = fieldMessage;
        }
      } else {
        console.warn(`MemberScript #195: Unknown validation type "${validationType}" for "${fieldName}". Use 'zip', 'phone', 'email', or 'regex'.`);
        return;
      }
      
      validationRules.push(rule);
      
      // Add event listeners
      if (CONFIG.OPTIONS.realTimeValidation) {
        input.addEventListener('input', () => validateField(rule));
      }
      
      if (CONFIG.OPTIONS.validateOnBlur) {
        input.addEventListener('blur', () => validateField(rule));
      }
    });
    
    // Add form submit handler
    if (CONFIG.OPTIONS.preventSubmit) {
      form.addEventListener('submit', handleFormSubmit);
      
      // Also handle click on submit button (works with both <button> and <a> tags)
      const submitButton = form.querySelector('button[type="submit"], input[type="submit"], a[type="submit"], [type="submit"]');
      if (submitButton) {
        submitButton.addEventListener('click', function(e) {
          const isValid = validateAllFields();
          
          if (!isValid) {
            e.preventDefault();
            e.stopPropagation();
            
            // Focus first invalid field
            const firstInvalid = validationRules.find(rule => {
              const value = rule.input.value.trim();
              if (rule.required && !value) return true;
              if (value && rule.pattern && !rule.pattern.test(value)) return true;
              return false;
            });
            
            if (firstInvalid) {
              firstInvalid.input.focus();
              firstInvalid.input.scrollIntoView({ behavior: 'smooth', block: 'center' });
            }
          } else {
            // If validation passes and it's a link, prevent default navigation and submit form
            if (submitButton.tagName === 'A' && (submitButton.href === '#' || submitButton.getAttribute('href') === '#')) {
              e.preventDefault();
              e.stopPropagation();
              form.submit();
            }
          }
        });
      }
    }
  }
  
  function validateField(rule) {
    const value = rule.input.value.trim();
    let isValid = true;
    let errorMessage = '';
    
    // Check required field
    if (rule.required && !value) {
      isValid = false;
      errorMessage = CONFIG.MESSAGES.required;
    }
    // Check pattern if value exists
    else if (value && rule.pattern && !rule.pattern.test(value)) {
      isValid = false;
      errorMessage = rule.message || CONFIG.MESSAGES.default;
    }
    
    // Show or hide error message
    if (isValid) {
      rule.errorElement.style.display = 'none';
      rule.input.classList.remove('validation-error');
      rule.input.classList.add('validation-valid');
    } else {
      rule.errorElement.style.display = 'block';
      rule.errorElement.textContent = errorMessage;
      rule.input.classList.add('validation-error');
      rule.input.classList.remove('validation-valid');
    }
    
    return isValid;
  }
  
  function validateAllFields() {
    let allValid = true;
    
    validationRules.forEach(rule => {
      if (!validateField(rule)) {
        allValid = false;
      }
    });
    
    return allValid;
  }
  
  function handleFormSubmit(event) {
    if (!validateAllFields()) {
      event.preventDefault();
      event.stopPropagation();
      
      // Focus first invalid field
      const firstInvalid = validationRules.find(rule => {
        const value = rule.input.value.trim();
        if (rule.required && !value) return true;
        if (value && rule.pattern && !rule.pattern.test(value)) return true;
        return false;
      });
      
      if (firstInvalid) {
        firstInvalid.input.focus();
        firstInvalid.input.scrollIntoView({ behavior: 'smooth', block: 'center' });
      }
    }
  }
  
  // ============================================================================
  // MODIFY: INITIALIZATION DELAY - Adjust if scripts load slowly (in milliseconds)
  // ============================================================================
  const INIT_DELAY = 100; // Increase to 200-500 if form loads slowly
  
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => setTimeout(init, INIT_DELAY));
  } else {
    setTimeout(init, INIT_DELAY);
  }
  
})();
</script>



Customer Showcase

Have you used a Memberscript in your project? We’d love to highlight your work and share it with the community!

Erstellen des Make.com-Szenarios

1. Laden Sie den JSON-Blaupause unten, um angegeben zu bekommen.

2. Navigieren Sie zu Make.com und erstellen Sie ein neues Szenario...

3. Klicken Sie auf das kleine Kästchen mit den 3 Punkten und dann auf Blaupause importieren...

4. Laden Sie Ihre Datei hoch und voila! Sie sind bereit, Ihre eigenen Konten zu verknüpfen.

Brauchen Sie Hilfe mit diesem MemberScript?

Alle Memberstack-Kunden können im 2.0 Slack um Unterstützung bitten. Bitte beachten Sie, dass dies keine offiziellen Funktionen sind und der Support nicht garantiert werden kann.

Treten Sie dem 2.0 Slack bei
Anmerkungen zur Version
Attribute
Beschreibung
Attribut
Keine Artikel gefunden.
Leitfäden / Tutorials
Keine Artikel gefunden.
Tutorial
Was ist Memberstack?

Autorisierung und Zahlungen für Webflow-Websites

Fügen Sie Ihrer Webflow-Website Logins, Abonnements, Gated Content und vieles mehr hinzu - einfach und vollständig anpassbar.

Mehr erfahren

"Wir verwenden Memberstack schon seit langem, und Es hat uns geholfen, Dinge zu erreichen, die wir mit Webflow nie für möglich gehalten hätten. Es hat uns ermöglicht, Plattformen mit großer Tiefe und Funktionalität zu bauen, und das Team dahinter war immer sehr hilfsbereit und offen für Feedback.

Jamie Debnam
39 Digital

"Ich habe eine Mitgliedschaftsseite mit Memberstack und Jetboost für einen Kunden erstellt. Es fühlt sich wie Magie an, mit diesen Tools zu bauen. Als jemand, der in einer Agentur gearbeitet hat, wo einige dieser Anwendungen von Grund auf neu programmiert wurden, verstehe ich jetzt endlich den Hype. Das ist viel schneller und viel billiger."

Félix Meens
Webflix-Studio

"Eines der besten Produkte, um eine Mitgliederseite zu starten - ich mag die Benutzerfreundlichkeit von Memberstack. Ich war in der Lage, meine Mitgliederseite innerhalb eines Tages einzurichten und zu betreiben.. Einfacher geht's nicht. Außerdem bietet es die Funktionalität, die ich brauche, um die Benutzererfahrung individueller zu gestalten."

Eric McQuesten
Gesundheitstechnologie-Nerds
Off World Depot

"Mein Geschäft wäre ohne Memberstack nicht das, was es ist. Wenn Sie denken, dass $30/Monat teuer sind, versuchen Sie mal, einen Entwickler zu engagieren, der für diesen Preis individuelle Empfehlungen in Ihre Website integriert. Unglaublich flexible Tools für diejenigen, die bereit sind, einige minimale Anstrengungen zu unternehmen und die gut zusammengestellte Dokumentation zu lesen."

Riley Brown
Off World Depot

"Die Slack-Community ist eine der aktivsten, die ich kenne, und andere Kunden sind bereit, Fragen zu beantworten und Lösungen anzubieten. Ich habe ausführliche Bewertungen von alternativen Tools durchgeführt und wir kommen immer wieder auf Memberstack zurück - sparen Sie sich die Zeit und probieren Sie es aus."

Abtei Burtis
Gesundheitstechnologie-Nerds
Slack

Brauchen Sie Hilfe mit diesem MemberScript? Treten Sie unserer Slack-Community bei!

Treten Sie der Memberstack-Community Slack bei und fragen Sie los! Erwarten Sie eine prompte Antwort von einem Team-Mitglied, einem Memberstack-Experten oder einem anderen Community-Mitglied.

Unserem Slack beitreten