SwiftListTreeDataSource
SwiftListTreeDataSource copied to clipboard
Search Not working
The search is not working as per the implementation in the example. I am unable to filter out the data based on search. Find the following code.
if textField.stringValue.isEmpty { self.cratesDataSource.resetFiltering(collapsingAll: true) self.outlineviewCrates.reloadData() } else { let searchText = textField.stringValue self.cratesDataSource.filterItemsKeepingParents(by: { $0.crateName! .localizedCaseInsensitiveContains(searchText)}) { [weak self] in guard let self = self else { return } self.outlineviewCrates.reloadData() } }
Hello @AKGupta31 , could you please share actual & expected behavior? Maybe you can just provide data set you're using and test cases?
I am using outline view for hierarical data like expandable listview.
Following Code:
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
if isSearchMode {
return cratesDataSource.items.count
}
guard let cratesDataSource = self.cratesDataSource else {
return 0
}
return item == nil ? cratesDataSource.backingStore.count : (item as? TreeItem<SeratoCrate>)?.subitems.count ?? 1
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
if isSearchMode {
return cratesDataSource.items[index]
}
if item == nil {
return cratesDataSource.backingStore[index]
}
return (item as? TreeItem<SeratoCrate>)?.subitems[index] ?? item!
}
The above code is to show the data. But backing store represents the same data every time. I think for this reason i am unable to filter the data. We must filter out the backing store as well as its subitems or can use some other variables in case of search..Since the below code is giving some filtered data but still with parents which i am not able to represent in hierarchy.
if isSearchMode {
return cratesDataSource.items[index]
}
Hello @AKGupta31 ,
- The
backingStore
is original hierarchical store and shouldn't be used directly (ideally). - The
items
should contain all the items after filtering (with parents that lead to search target items)
I haven't used NSOutlineView, so just trying some ideas:
- Return
items
as data source count - For outlineView(_, numberOfChildrenOfItem:) use
guard let item = item as? TreeItem<SeratoCrate> else {
// filter for roots only
return cratesDataSource.items.filter { $0.parent == nil }.count
}
return item.subitems.count
- For child(_, ofItem:) -> Any? use
guard let item = item as? TreeItem<SeratoCrate> else {
// filter for roots only
return cratesDataSource.items.filter { $0.parent == nil }[index]
}
return item.subitems[index]
Discussion: Original inspiration for current API subset was NSDiffableDataSourceSnapshot I see APIs NSOutlineView differs & tries to know all hierarchical structure what makes it little bit more complicated.
Please feel free to submit archive with sample app so we can improve it and make use-case running. Thanks!
Hi @dzmitry-antonenka , The above code is almost fine for me. But just one point is left. Explained below.
Suppose there is one child named
Hi @dzmitry-antonenka ,
The above code is almost fine for me.
But just one point is left. Explained below.
Suppose there is one child named
inside a parent (root) . If i am searching for
then i must get the parent as expanded by default while searching but its showing the parent only. If you can help me out achieving the same.
You mean 'items' doesn't contain target search item but only parent? Or expanded not true for them. Are you sure target item matches filter criteria?
search logic we expand search target item parent (path to be visible for all items)
https://github.com/dzmitry-antonenka/SwiftListTreeDataSource/blob/a7e697180d09d391f67ce9bea233e12b7924beb4/Sources/SwiftListTreeDataSource/FilterableListTreeDataSource.swift#L48
No pressure, but please feel free to attach simple use case model you try in sample app and expected vs. actual behavior. In this case it would be more productive to support with this
Please feel free to share data source memory dump for inputs and outputs. Could you also try debug section to see what's the root cause?
Hi @dzmitry-antonenka , I need a functionality similar to this...
https://github.com/dzmitry-antonenka/SwiftListTreeDataSource/assets/51131294/65df2558-f551-435a-91ef-88065319fdc0
Hi @dzmitry-antonenka , I need a functionality similar to this...
ScreenRecording.mov
Right, that's exactly what our example apps are doing:
Could you please explore these code these snippets carefully? Example for performing search
func performSearch(with searchText: String) {
if !searchText.isEmpty {
self.searchBar.isLoading = true
self.displayMode = .filtering(text: searchText)
self.listTreeDataSource.filterItemsKeepingParents(by: { $0.title.lowercased().contains(searchText.lowercased()) }) { [weak self] in
guard let self = self else { return }
self.searchBar.isLoading = false
self.reloadUI(animating: false)
}
} else {
self.displayMode = .standard
self.searchBar.isLoading = false
self.listTreeDataSource.resetFiltering(collapsingAll: true)
self.reloadUI(animating: false)
}
}
After self.listTreeDataSource.filterItemsKeepingParents
self.listTreeDataSource.items should contain all search items and their parents. Could you please examine this property to validate filter logic? Maybe small data set can be helpful
@AKGupta31 ,
From debugging section
// to get testable
access to internal stuff, including to backingStore
.
@testable import SwiftListTreeDataSource
// Make conform to CustomDebugStringConvertible
.
extension OutlineItem: CustomDebugStringConvertible {
public var debugDescription: String { "(title)" }
}
// Correct usage:
let output1 = debugDescriptionTopLevel(listTreeDataSource.items) // ✅ Description for top level since items
already flattened (one-level perspective) and include expanded children.
Try this to see what output after filtering it provides?
@AKGupta31 do you have any updates on this? Please feel free to post simple example project or use existing TreeView projects with your data set. Describe Actual vs Expected results so we can investigate. Thank you!