A flexible and extensible forms with easy-to-use validation. This library build for SwiftUI
and inspired by Reactive forms of Angular.
- In Xcode, open your project and navigate to File → Swift Packages → Add Package Dependency...
- Paste the repository URL (
https://github.com/hollyoops/ReactiveForm.git
) and finish import
ReactiveForm is available through CocoaPods. To install it, simply add the following code to your Podfile:
pod 'ReactiveForm'
import SwiftUI
import ReactiveForm
class ProfileForm: ObservableForm {
@FormField(validators: [.required])
var name = ""
@FormField(validators: [.required, .email])
var email = ""
}
struct ContentView: View {
@StateObject var form = ProfileForm()
var body: some View {
Form {
TextField("Name", text: $form.firstName)
if form.$name.isInValid {
Text("Please fill a name.")
.foregroundColor(.red)
}
TextField("Email", text: $form.email)
if form.$email.isInValid {
Text("Please fill a valid email")
.foregroundColor(.red)
}
}
}
}
let stringValidator = Validator { stringValue: String -> Bool
// some check logic
return true
}
class ProfileForm: ObservableForm {
@FormField(validators: [.required, stringValidator])
var name = ""
}
You are not a big fan of property wrapper, you can build a form using ObservableForm
and FormControl
.
class ProfileForm: ObservableForm {
var name = FormControl("", validators: [.required])
var email = FormControl("", validators: [.required, .email])
}
For some case, you may need to manually call validate
rather than validate on change
class ProfileForm: ObservableForm {
@FormField("", validators: [.required], type: .manually)
var name: String
@FormField("", validators: [.email], type: .manually)
var email: String
}
struct ContentView: View {
@StateObject var form = ProfileForm()
var body: some View {
Form {
TextField("Name", text: $form.name.pendingValue)
if form.$name.errors[.required] {
Text("Please fill a name.")
.foregroundColor(.red)
}
TextField("Email", text: $form.email.pendingValue)
if form.$email.errors[.email] {
Text("Please fill a valid email.")
.foregroundColor(.red)
}
Button(action: submit) {
Text("Submit")
}
}
}
func submit() {
// You can call `validate` manually
form.validate()
if form.isValid {
print(form)
}
}
}
You can use isDirty
& isPristine
to check where form is edited.
One possible scenario is when page appear you don't want to show error util form is edited.
class SettingsForm: ObservableForm {
var name = FormControl("", validators: [.required], type: .manually)
var email = FormControl("", validators: [.email], type: .manually)
}
struct ContentView: View {
@StateObject var form = SettingsForm()
var body: some View {
Form {
TextField("Name", text: $form.name.value)
if form.name.isDirty && form.name.errors[.required] {
Text("Please fill a name.")
.foregroundColor(.red)
}
TextField("Email", text: $form.email.value)
if form.email.isDirty && form.email.errors[.email] {
Text("Please fill a valid email.")
.foregroundColor(.red)
}
Button(action: submit) {
Text("Submit")
}
.disabled(form.isInvalid)
}
}
}