I have a mini macOS app, presenting some data persisted in SwiftData on a Table.
I want to sort the data by clicking on Table's column headers so I have a KeyPathComparator on the table.
But since the result of @Query is get-only, I am not able to set sort of items.
Any suggestions?
Here is my table:
@Query private var items: [Product]
@State private var sortOrder = [KeyPathComparator(\Product.category?.name)]
var body: some View {
Table(items, sortOrder: $sortOrder) {
TableColumn("Category",value: \.category!.name)
TableColumn("Design", value: \.design!.name)
TableColumn("Market", value: \.market!.name)
TableColumn("Link", value: \.link)
}
.onChange(of: sortOrder, { oldValue, newValue in
items.sort(using: newValue) // ERROR: Cannot use mutating member on immutable value: 'items' is a get-only property
})
}
As mentioned in the comments, @Query and Table doesn't work that well together at least not when it comes to sorting. Here is one way to work around it by having a second array as a computed properties that gets sorted on the Table's sort order parameter.
@Query private var items: [Product]
@State private var sortOrder = [KeyPathComparator(\Product.category?.name)]
var sortedItems: [Product] {
items.sorted(using: sortOrder)
}
var body: some View {
Table(sortedItems, sortOrder: $sortOrder) {
TableColumn("Category",value: \.category!.name)
TableColumn("Design", value: \.design!.name)
TableColumn("Market", value: \.market!.name)
TableColumn("Link", value: \.link)
}
}
If one uses the Table(...) { ... } rows: {...} form then you can skip the computed property and sort in the ForEach directly
Table(of: Product.self, sortOrder: $sortOrder) {
TableColumn...
} rows: {
ForEach(items.sorted(using: sortOrder)) {
TableRow($0)
}
}
I am not sure if it makes any difference performance/memory wise but it's a bit less code.
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