I'm trying to bind an array of strings into their corresponding text fields in a scrolling list. The number of rows is variable, and corresponds to the number of elements in the string array. The user can add or delete rows, as well as changing the text within each row.
The following Playground code is a simplified version of what I'm trying to achieve.
import SwiftUI
import PlaygroundSupport
struct Model {
struct Row : Identifiable {
var textContent = ""
let id = UUID()
}
var rows: [Row]
}
struct ElementCell: View {
@Binding var row: Model.Row
var body: some View {
TextField("Field",text: $row.textContent)
}
}
struct ElementList: View {
@Binding var model: Model
var body: some View {
List {
ForEach($model.rows) {
ElementCell(row: $0)
}
}
}
}
struct ContentView: View {
@State var model = Model(rows: (1...10).map({ Model.Row(textContent:"Row \($0)") }))
var body: some View {
NavigationView {
ElementList(model: $model)
}
}
}
PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())
The issue is that I can't seem to get the "cell" to bind correctly with its corresponding element. In the example code above, Xcode 11.1 failed to compile it with error in line 26:
error: Text-Field Row.xcplaygroundpage:26:13: error: cannot invoke initializer for type 'ForEach<_, _, _>' with an argument list of type '(Binding<[Model.Row]>, @escaping (Binding<Model.Row>) -> ElementCell)'
ForEach($model.rows) {
^
Text-Field Row.xcplaygroundpage:26:13: note: overloads for 'ForEach<_, _, _>' exist with these partially matching parameter lists: (Data, content: @escaping (Data.Element) -> Content), (Range<Int>, content: @escaping (Int) -> Content)
ForEach($model.rows) {
^
What would be the recommended way to bind elements that are a result of ForEach into its parent model?