Since Swift 5.5 we could create SwiftUI lists with bindings like this (e.g. see this answer):
class Item {
// ...
var isOn: Bool
}
struct ContentView: View {
@State private var items: [Item] = []
var body: some View {
NavigationView {
List {
ForEach($items) { $item in // <--- list binding
Toggle(isOn: $item.isOn) {
Text("Vibrate on Ring")
}
}
}
}
}
}
Now I want to do something similar with SwiftData but I get an error:
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [Item]
var body: some View {
NavigationView {
List {
ForEach($items) { $item in // <--- Cannot find '$items' in scope
// ...
How can I render a list of SwiftData objects that allows inline editing of objects through bindings?
You can utilize the new Bindable
, which has a subscript operator to wrap the underlying data into a binding variable:
ForEach(items) { item in
Toggle(isOn: Bindable(item).isOn) { ... }
}
If the binding need to be reused multiple times, you can also create the Bindable
object within the view:
ForEach(items) { item in
@Bindable var item = item
Toggle(isOn: $item.isOn) { ... }
}
Note the usage of $
, since the bindable object is created as a property wrapper.
The easiest solution I found is to use @Bindable and to separate the Query
macro and the Bindable
into different views.
An example
struct ItemRow: View {
@Bindable var item: Item
var body: some View {
HStack {
Text(item.name)
Toggle(isOn: $item.isOn) // Notice the $
}
}
}
Calling view
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [Item]
var body: some View {
NavigationView {
List {
ForEach(items) { item in
ItemRow(item: item)
//...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With