The detail view / the destination of the NavigationSplitView
does not change when selecting another item in the sidebar.
Given a Swift Data Model
@Model final class MyModel {
var text: String
init(text: String) {self.text = text}
}
And a NavigationSplitView, that should display all of those models plus an edit view
struct MyModelEditView: View {
@Environment(.modelContext) var modelContext
@State var myModel: MyModel
var body: some View {
TextField("Edit Text", text: $myModel.text)
}
}
struct ContentView: View {
@Environment(.modelContext) var modelContext
@Query var models: [MyModel]
var body: some View {
NavigationSplitView {
List {
ForEach(myModels) { model in
NavigationLink {
MyModelEditView(myModel: model)
.modelContext(modelContext)
} label: {
Text(model.text)
}
}
}
} detail: {
Text("Tap plus for a new model")
}
// we pretend that here is a button in a toolbar that adds a new model
}
When initially clicking on any item in the list, the detail view for this item is displayed! But when clicking on another model, the detail view just stays where it was, with the previous model.
I also tried to create an
@State var selectedModel: MyModel
and using the List initializer List(selection: $selectedModel)
, tagging each item in the ForEach
(.tag(model)
) instead of using NavigationLink
and then in the detail block:
detail: {
if let selectedModel {
MyModelEditView(myModel: myModel)
.modelContext(modelContext)
} else {
Text("Tap plus for a new model")
}
}
…
But also this did not help.
I’ve found out that .navigationDestination(for:)
is limited to NavigationStack
, so I am left with no idea how to make a working Navigation Stack for my SwiftData models.
! Note that this is not specific to SwiftData models as objects, this does also happen with any Kind of structs or classes, I tried it with a struct containing just a single String such as the MyModel
class.
2
Answers
I've found the fix after a lot of trial and error. The solution was simply to do this in the List:
As of what I have read, .id forces the detail view to be drawn again every time.
I am not sure if this is the most elegant way of doing this, but it works.
As suggested in the comments,
@Bindable
will fix the issue without having to use another view modifier.