ObservedResults filtering and sorting

Hi,

I just started playing with the new property wrappers and I have a question regarding ObservedResults. Let’s say I have a collection of items and I want to display only a subset of it:

@ObservedResults(Item.self, filter: NSPredicate(format: "lastName begins with A")) var itemList

Later I would like to further filter that subset using a search field:

.onChange(of: searchText, perform: { searchString in itemList.filter = NSPredicate(format: "firstName begins with %@", searchString) })

Everything is working as expected but, when I clear the search field, I get back all the items without any filter (all the Item records from realm). And if, for any reason, SwiftUI re-renders the view, then I get the items properly filtered.

The comment within the ObservedResults implementation says:

A base value to reset the state of the query if a user reassigns the filter or sortDescriptor

value = try! Realm(configuration: configuration ?? Realm.Configuration.defaultConfiguration).objects(ResultType.self)

That means whenever the filter or the sort descriptor is changed, all the items are received, right?

Is there any way to have returned only the items as they were queried in the beginning?

I hope I made myself clear.

Thank you!

Horatiu

1 Like

Could you send us a small, self contained view/views that shows a good use case for this? I intentionally didn’t allow for sub filtering when designing the feature.

Bellow is a snippet of a more generic implementation of a List:

`import SwiftUI
import RealmSwift

struct ListView<T: Object, RowView: View, DetailView: View>: View where T: ObjectKeyIdentifiable {

@ObservedResults(T.self, filter: NSPredicate(format: "documentDate BETWEEN {startDate, endDate}")) var results

let rowView: (T) -> RowView
let detailView: (T) -> DetailView

@State var selectedRow: T?

@State var searchText: String = ""

init(@ViewBuilder rowView: @escaping (T) -> RowView, @ViewBuilder detailView: @escaping (T) -> DetailView) {
    self.rowView = rowView
    self.detailView = detailView
}

var body: some View {
    
    List(selection: $selectedRow) {
        ForEach(results) { row in
            rowView(row)
                .tag(row)
        }
    }
    .frame(minWidth: 300)
    .listStyle(InsetListStyle())
    .toolbar {
        SearchField(searchText: $searchText)
            .frame(minWidth: 150, idealWidth: 200, maxWidth: .infinity)
        Spacer()
        Button(action: { }, label: { Image("plus") })
    }
    .onChange(of: searchText, perform: { searchString in
        $results.filter = searchString.isEmpty ? nil : NSPredicate(format: "companyName BEGINS WITH %@", searchString)
    })
}

}`

Let’s assume we have an invoicing app and we want to retrieve only the documents within a specific month/period. Then we can search for the documents belonging to a specific customer.

But, as long as I clear the search field, I get all the results from realm not only those within the date range specified in the predicate. And on next rendering the results are updated correctly. For example, if the app window becomes inactive the results are updated and filtered properly.

The same thing can be applied to sortDescriptor where we can have an initial sorting and then use a control to sort the results as we want. Like NSTableView sorting headers.

did this ever get resolved? I am having a similar issue.

I believe using Realm’s .searchable implementation preserves the NSPredicate or Query injected initially into @ObservedResults.

1 Like