I have a NavigationStack with parent view
struct MainDatabaseView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
List {
Section {
NavigationLink(destination: MainTabPilotDatabaseView(path: $path)) {
Label("Pilots", systemImage: "person.2")
.foregroundStyle(.primary)
}
NavigationLink(destination: MainTabAircraftDatabaseView()) {
Label("Aircraft", systemImage: "airplane.circle")
.foregroundStyle(.primary)
}
} header: {
Text("Database")
}
}
}
}
And a child view
struct MainTabPilotDatabaseView: View {
@EnvironmentObject var pilotVM: PilotVM
@Binding var path : NavigationPath
var body: some View {
List {
ForEach(pilotVM.filteredPilots, id: \.id) { pilot in
NavigationLink {
PilotDatabaseDetailView(pilot: pilot)
} label: {
PilotCell(pilot: pilot, isInDetailView: false)
.contentShape(Rectangle())
.swipeActions(edge: .trailing) { delete(for: pilot) }
.swipeActions(edge: .leading) { markFavorite(for: pilot) }
}
}
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) { addPilot() }
}
}
func addPilot() -> some View {
Button {
let pilotModelInput = PilotModelInput()
let new = pilotVM.addPilotToModel(input: pilotModelInput)
path.append(new)
} label: {
Image(systemName: "plus.circle.fill")
}
}
}
When I have path as @State var path: [PilotEntity] = []
the code works as expected - i.e. when plus.circle.fill button in child view is tapped, it pushes a sub-child view in the NavigationStack. However since I will also be using a different entity (AircraftEntity) for the other view in the NavigationStack, I presume that I have to go with generic NavigationPath.
I have the code mock as above and cannot seem to pass the data to the sub-child view. What is the best way of going about it?
EDIT:
I have been playing with the solution from @son and found that this also works:
import SwiftUI
enum DatabaseTabOption {
case pilot, aircraft
}
class NavigationStackManager: ObservableObject {
@Published var path = NavigationPath()
}
struct MainDatabaseView: View {
@StateObject var pathManager = NavigationStackManager()
var body: some View {
NavigationStack(path: $pathManager.path) {
List {
Section {
NavigationLink(value: DatabaseTabOption.pilot) {
Button {
pathManager.path.append(DatabaseTabOption.pilot)
} label: {
Label("Pilots", systemImage: "person.2")
}
}
NavigationLink(value: DatabaseTabOption.aircraft) {
Button {
pathManager.path.append(DatabaseTabOption.aircraft)
} label: {
Label("Aircraft", systemImage: "airplane.circle")
}
}
} header: {
Text("Database")
}
}
.navigationDestination(for: DatabaseTabOption.self, destination: { value in
switch value {
case .pilot:
MainTabPilotDatabaseView()
.environmentObject(pathManager)
case .aircraft:
MainTabAircraftDatabaseView()
.environmentObject(pathManager)
}
})
}
}
}
I am passing enum on the parent level. I am wrapping the Buttons in NavigationLink
in order to get the navigation prompts (chevrons) back. In child view I can then append any other type to the path. Thanks to @son for steering me onto the right path.
NavigationPath
can append generic type which conforms Hashable. So you can totally addAircraftEntity
since this model conforms to the Hashable protocol. And change.navigationDestination
for this type.Also, multiple types in the same context: