Form Validation trong SwiftUI
1. Basic Validation
struct SignUpForm: View {
@State private var email = ""
@State private var password = ""
var isEmailValid: Bool {
email.contains("@") && email.contains(".")
}
var isPasswordValid: Bool {
password.count >= 8
}
var isFormValid: Bool {
isEmailValid && isPasswordValid
}
var body: some View {
Form {
TextField("Email", text: $email)
if !email.isEmpty && !isEmailValid {
Text("Invalid email format")
.foregroundColor(.red)
.font(.caption)
}
SecureField("Password", text: $password)
if !password.isEmpty && !isPasswordValid {
Text("Password must be at least 8 characters")
.foregroundColor(.red)
.font(.caption)
}
Button("Sign Up") { }
.disabled(!isFormValid)
}
}
}2. Real-time Validation
struct ValidatedTextField: View {
let label: String
@Binding var text: String
let validation: (String) -> Bool
let errorMessage: String
var body: some View {
VStack(alignment: .leading, spacing: 4) {
TextField(label, text: $text)
.textFieldStyle(.roundedBorder)
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(
!text.isEmpty && !validation(text) ? .red : .clear,
lineWidth: 1
)
)
if !text.isEmpty && !validation(text) {
Text(errorMessage)
.foregroundColor(.red)
.font(.caption)
}
}
}
}
// Usage
ValidatedTextField(
label: "Email",
text: $email,
validation: { $0.contains("@") },
errorMessage: "Please enter a valid email"
)3. Form với ViewModel
class FormViewModel: ObservableObject {
@Published var email = ""
@Published var password = ""
@Published var confirmPassword = ""
var emailError: String? {
guard !email.isEmpty else { return nil }
return email.contains("@") ? nil : "Invalid email"
}
var passwordError: String? {
guard !password.isEmpty else { return nil }
if password.count < 8 { return "Too short" }
return nil
}
var confirmError: String? {
guard !confirmPassword.isEmpty else { return nil }
return password == confirmPassword ? nil : "Passwords don't match"
}
var isValid: Bool {
emailError == nil && passwordError == nil && confirmError == nil
&& !email.isEmpty && !password.isEmpty && !confirmPassword.isEmpty
}
}4. Submit Button State
Button {
// Submit
} label: {
if isLoading {
ProgressView()
} else {
Text("Submit")
}
}
.disabled(!isFormValid || isLoading)
.opacity(isFormValid ? 1 : 0.5)📝 Best Practices
- Validate on change, not just on submit
- Show errors near the field
- Disable submit until valid
- Use ViewModel for complex validation
Last updated on