Skip to content

Component-Specific Validation Logic

Overview

Hver form input-komponent håndterer sin egen spesialiserte validering og input-prosessering, mens de deler felles konfigurasjon via useInputValidation.

Input-Specific Logic

FormTextInput & FormEmailInput

typescript
handleInput(value: string) {
  // Prevent typing beyond max length (better UX)
  let processedValue = value
  
  if (this.maxLength && processedValue.length > this.maxLength) {
    processedValue = processedValue.substring(0, this.maxLength)
  }
  
  this.$emit('input', processedValue)
}

FormPhoneInput

typescript
handleInput(inputValue: string) {
  // Remove non-numeric characters
  let cleanValue = inputValue.replace(/\D/g, '')
  
  // Apply maxLength constraint
  if (this.maxLength && cleanValue.length > this.maxLength) {
    cleanValue = cleanValue.substring(0, this.maxLength)
  }
  
  this.$emit('input', cleanValue)
}

handleKeydown(event: KeyboardEvent) {
  // Block non-numeric input at keyboard level
  const allowedKeys = ['Backspace', 'Delete', 'Tab', 'Escape', 'Enter', ...]
  
  if (!/^[0-9]$/.test(event.key) && !allowedKeys.includes(event.key)) {
    event.preventDefault()
  }
}

FormNumberInput

typescript
// Uses HTML5 number input with min/max/step attributes
computed: {
  minValue() {
    const val = parseFloat(this.validation.min)
    return isNaN(val) ? undefined : val
  },
  
  maxValue() {
    const val = parseFloat(this.validation.max)
    return isNaN(val) ? undefined : val
  },
  
  stepValue() {
    const val = parseFloat(this.validation.step)
    return isNaN(val) ? 'any' : val
  }
}

FormDateInput

typescript
handleChange(inputValue: string) {
  if (this.isValidDate(inputValue)) {
    this.$emit('input', inputValue)
  }
}

isValidDate(dateString: string) {
  if (!dateString) return !this.isRequired
  
  const inputDate = new Date(dateString)
  
  // Check if valid date
  if (isNaN(inputDate.getTime())) return false
  
  // Check min/max date constraints
  if (this.minDate && inputDate < new Date(this.minDate)) return false
  if (this.maxDate && inputDate > new Date(this.maxDate)) return false
  
  return true
}

FormTextAreaInput

typescript
computed: {
  rows() {
    const val = parseInt(this.input.rows)
    return isNaN(val) ? 3 : Math.max(1, val)
  },
  
  resizable() {
    return this.input.resizable !== false
  }
}

// Template uses dynamic rows and resize styling
:rows="rows"
:style="{ resize: resizable ? 'vertical' : 'none' }"

Shared Configuration Pattern

Alle komponenter følger samme mønster:

typescript
import { useInputValidation } from '@/composables/useInputValidation'

setup(props) {
  const {
    validation,
    isRequired,
    minLength,
    maxLength,
    placeholder,
    pattern
  } = useInputValidation(props.input)

  return { validation, isRequired, minLength, maxLength, placeholder, pattern }
}

Fordeler

  1. Spesialisert UX per input-type:

    • Phone: Kun numeriske tegn
    • Email: Pattern validation
    • Date: Min/max date constraints
    • Number: Step/min/max constraints
  2. Konsistent konfigurasjon:

    • Alle bruker samme validation properties
    • Felles placeholder/required logic
  3. Fleksibel arkitektur:

    • Lett å legge til nye input-typer
    • Hver komponent kan ha unik logikk
  4. Bedre vedlikehold:

    • Endringer i én input-type påvirker ikke andre
    • Klar separasjon av ansvar

Internal documentation