Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftData list bindings with @Query

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?

like image 887
de. Avatar asked Sep 13 '25 17:09

de.


2 Answers

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.

like image 194
Ranoiaetep Avatar answered Sep 15 '25 07:09

Ranoiaetep


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)
     //...
}
like image 29
Joakim Danielson Avatar answered Sep 15 '25 07:09

Joakim Danielson