Skip to content

Commit 0f1e57f

Browse files
Victor KostinVictor Kostin
authored andcommitted
Аdd the ability to track validation without action
1 parent 05f63a4 commit 0f1e57f

5 files changed

Lines changed: 36 additions & 4 deletions

File tree

ExampleApp/ExampleApp/UI/ContentScreen/ContentView.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ import FormView
1010

1111
struct ContentView: View {
1212
@ObservedObject var viewModel: ContentViewModel
13+
@State var isAllFieldValid = false
1314

1415
var body: some View {
1516
FormView(
1617
validate: [.manual, .onFieldValueChanged, .onFieldFocus],
17-
hideError: .onValueChanged
18+
hideError: .onValueChanged,
19+
isAllFieldValid: $isAllFieldValid
1820
) { proxy in
1921
FormField(
2022
value: $viewModel.name,
@@ -52,7 +54,7 @@ struct ContentView: View {
5254
print("Form is valid: \(await proxy.validate())")
5355
}
5456
}
55-
.disabled(viewModel.isLoading)
57+
.disabled(isAllFieldValid == false || viewModel.isLoading)
5658
}
5759
.padding(.horizontal, 16)
5860
.padding(.top, 40)

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ struct MyField: View {
5757
```swift
5858
struct ContentView: View {
5959
@State var name: String = ""
60+
@State var isAllFieldValid = false
6061

6162
var body: some View {
6263
FormView( First failed field
6364
validate: .never, // Form will be validated on user action.
64-
hideError: .onValueChanged // Error for field wil be hidden on field value change.
65+
hideError: .onValueChanged, // Error for field wil be hidden on field value change.
66+
isAllFieldValid: $isAllFieldValid // Property indicating the result of validation of all fields without focus
6567
) { proxy in
6668
FormField(
6769
value: $name,
@@ -74,6 +76,7 @@ struct ContentView: View {
7476
// Validate form on user action.
7577
print("Form is valid: \(proxy.validate())")
7678
}
79+
.disabled(isAllFieldValid == false) // Use isAllFieldValid to automatically disable the action button
7780
}
7881
}
7982
}
@@ -92,6 +95,9 @@ Error for each field gets hidden at one of three specific times:
9295
* `onFocus` - field with error is focused..
9396
* `onFucusLost` - field with error lost focus.
9497

98+
### Is All Field Valid
99+
Property indicating the result of validation of all fields without focus. Using this property you can additionally build ui update logic, for example block the next button.
100+
95101
### Custom Validation Rules
96102
One of two ways:
97103
1. Adopt protocol `ValidationRule`:
@@ -224,7 +230,7 @@ FormView doesn't use any external dependencies.
224230
dependencies: [
225231
.package(
226232
url: "https://github.com/MobileUpLLC/FormView",
227-
.upToNextMajor(from: "1.1.2")
233+
.upToNextMajor(from: "1.3.0")
228234
)
229235
]
230236
```

Sources/FormView/FormField.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public struct FormField<Content: View>: View {
1212
@ViewBuilder private let content: ([ValidationRule]) -> Content
1313

1414
@State private var failedValidationRules: [ValidationRule] = []
15+
private var isValid: Bool { failedValidationRules.isEmpty && value.isEmpty == false }
1516

1617
// Fields Focus
1718
@FocusState private var isFocused: Bool
@@ -57,6 +58,7 @@ public struct FormField<Content: View>: View {
5758
}
5859
]
5960
)
61+
.preference(key: FieldsValidationKey.self, value: [isValid])
6062
.focused($isFocused)
6163

6264
// Fields Validation

Sources/FormView/FormView.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ private class FormStateHandler: ObservableObject {
6363

6464
public struct FormView<Content: View>: View {
6565
@StateObject private var formStateHandler = FormStateHandler()
66+
@Binding private var isAllFieldValid: Bool
6667
@ViewBuilder private let content: (FormValidator) -> Content
6768

6869
private let errorHideBehaviour: ErrorHideBehaviour
@@ -71,11 +72,13 @@ public struct FormView<Content: View>: View {
7172
public init(
7273
validate: [ValidationBehaviour] = [.manual],
7374
hideError: ErrorHideBehaviour = .onValueChanged,
75+
isAllFieldValid: Binding<Bool> = .constant(true),
7476
@ViewBuilder content: @escaping (FormValidator) -> Content
7577
) {
7678
self.content = content
7779
self.validationBehaviour = validate
7880
self.errorHideBehaviour = hideError
81+
self._isAllFieldValid = isAllFieldValid
7982
}
8083

8184
public var body: some View {
@@ -85,6 +88,9 @@ public struct FormView<Content: View>: View {
8588
.onPreferenceChange(FieldStatesKey.self) { [weak formStateHandler] newStates in
8689
formStateHandler?.updateFieldStates(newStates: newStates)
8790
}
91+
.onPreferenceChange(FieldsValidationKey.self) { validationResults in
92+
isAllFieldValid = validationResults.contains(false) == false
93+
}
8894
.onSubmit(of: .text) { [weak formStateHandler] in
8995
formStateHandler?.submit()
9096
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// FieldsValidationKey.swift
3+
// FormView
4+
//
5+
// Created by Victor Kostin on 31.03.2025.
6+
//
7+
8+
import SwiftUI
9+
10+
struct FieldsValidationKey: PreferenceKey {
11+
static var defaultValue: [Bool] = []
12+
13+
static func reduce(value: inout [Bool], nextValue: () -> [Bool]) {
14+
value += nextValue()
15+
}
16+
}

0 commit comments

Comments
 (0)