how do I achieve the following?
I have a TextField, and I want to create a configuration for it so that I can reuse it multiple times.
I'm using formatting, which is important because it's causing an issue here. However, everything works correctly if I move the 'text' and 'error' properties and bind them as '@State' to the view or use them as an 'ObservableObject'.
Here, you can see the issue. I'm encountering an error, and when I start typing, the table should disappear, but the cursor shouldn't jump to the beginning if I want to continue editing.
Can you suggest how I can improve this struct, or should I consider working with a class that conforms to ObservableObject?
struct Config {
@Binding public var text: String
@Binding public var error: String?
init(text: Binding<String>, error: Binding<String?>) {
_text = text
_error = error
}
}
struct ContentView: View {
var config: Config
init(config: Config) {
self.config = config
}
var body: some View {
VStack {
TextField("Enter text",
value: config.$text,
format: .numberFormatStyle)
if let error = config.error {
Text(error)
.foregroundStyle(.red)
}
Button("Validate") {
if config.text != "ABC" {
config.error = "Not valid text"
}
}
}
.padding()
.onChange(of: config.text) {
config.error = nil
}
}
}
struct NumberParseStrategy: ParseStrategy {
func parse(_ value: String) throws -> String {
value
}
}
struct NumberFormatStyle: ParseableFormatStyle {
var parseStrategy: NumberParseStrategy { .init() }
func format(_ value: String) -> String {
value
.lazy
.filter { $0 != " " }
.chunks(ofCount: 3)
.map { String($0) }
.joined(separator: "-")
}
}
extension ParseableFormatStyle where Self == NumberFormatStyle {
static var numberFormatStyle: NumberFormatStyle { .init() }
}
extension Array {
func chunks(ofCount chunkCount: Int) -> [[Element]] {
var result: [[Element]] = []
for index in stride(from: 0, to: count, by: chunkCount) {
let lastIdx = Swift.min(count, index + chunkCount)
result.append(Array(self[index ..< lastIdx]))
}
return result
}
}
@main
struct FormattedTextFIeldApp: App {
@State var text = ""
@State var error: String?
var body: some Scene {
WindowGroup {
ContentView(config: Config(text: $text, error: $error))
}
}
}