I have a navigation view with a list in my content view. In my list there is a ForEach that is passed an array. If I pass the ForEach just the array, everything works fine. If I filter that array, it will pop back anytime a change is made to a variable inside the array. I have a similar question that I already posted which has an answer (to use .stack navigation style). The navigation view is utilizing the .stack style. You can see in the code below that the array is filtered to show books that haven't been finished. In BookView there is a toggle that will set if the book is finished or not. My question, is there a way to stop it from popping back when using a filtered list?
NavigationView {
List {
ForEach(user.books.filter({$0.finished == false})) { book in
NavigationLink(destination: {
BookView(book: $user.books.first(where: {$0.id == book.id})!)
}, label: {
BookListItem(book: book)
})
}
.listStyle(.plain)
.searchable(text: $search, placement: .automatic, prompt: "Search")
.navigationTitle("Books")
.toolbar(content: {
ToolbarItemGroup(placement: .bottomBar, content: {
HStack {
Button(action: {
settings.toggle()
}, label: {
Text("Settings")
})
Spacer()
Button(action: {
addBook.toggle()
}, label: {
Text("Add Book")
})
}
})
})
.sheet(isPresented: $addBook, onDismiss: {}, content: {
AddBookView(user: $user)
})
.sheet(isPresented: $settings, onDismiss: {}, content: {
SettingsView(user: $user)
})
.sheet(isPresented: $editBook, onDismiss: {
//Clear editing book
editingBook = nil
}, content: {
EditBookView(user: $user,
book: $user.books.first(where: {$0.id == editingBook!.id})!,
sheet: $editBook,
name: editingBook!.name,
kind: editingBook!.kind,
author: editingBook!.author ?? "",
iconColor: editingBook!.iconColor)
})
}
.navigationViewStyle(.stack)
This is the Book model to help replicate the issue.
struct Book: Identifiable, Codable, Hashable {
enum Kind: String, Hashable, CaseIterable, Codable {
case fiction = "Fiction"
case nonfiction = "Nonfiction"
}
//Needs at creation
var name: String //Book name
var kind: Kind //Book kind
var finished: Bool //If book is finished
}
Toggle in the BookView
Toggle("Finished Reading", isOn: $book.finished)
Weirdly enough, when I used a computed property to search through the array, it will work okay. You can type something in the search bar, click on an item from the now filtered list, set the book to finished, and it won't pop back. It only seems to be an issue when I'm trying to filter by if the books are finished or not.
var searchedBooks: [Book] {
if search.isEmpty {
return user.books
} else {
//Lowercase the words when filtering
return filteredBooks.filter({
$0.name.lowercased().contains(search.lowercased().trimmed()) || //See if any of the book names contain what's in the search
$0.kind.rawValue.lowercased().contains(search.lowercased().trimmed()) //Check for fiction or nonfiction
})
}
}