Search code examples
swiftuiswiftui-listswiftui-navigationlink

How can I navigate to a detail view of an item by using an @EnvironmentObject to route the views?


I have the following code in SwiftUI. I am expecting it to navigate from the list view to the PetView() with the proper name showing when tapping on one of the items in the ForEach loop or the button that says "Go to first pet". However, when I tap on an item or the button, the app doesn't do anything. What am I doing wrong? Thank you for your help!



import SwiftUI

@main
struct TestListAppApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(ViewRouter())
        }
    }
}



import SwiftUI

struct ContentView: View {
    @EnvironmentObject var viewRouter: ViewRouter

    
    var body: some View {
            
            ForEach(viewRouter.pets) { pet in
                NavigationLink(
                    destination: PetView(),
                    tag: pet,
                    selection: $viewRouter.selectedPet,
                    label: {
                        Text(pet.name)
                    }
                )
            }
            
            Button("Go to first pet.") {
                viewRouter.selectedPet = viewRouter.pets[0]
            }
    
        
}
    
}


import Foundation

class ViewRouter: ObservableObject {
    @Published var selectedPet: Pet? = nil
    @Published var pets: [Pet] = [Pet(name: "Louie"), Pet(name: "Fred"), Pet(name: "Stanley")]
}



import SwiftUI

struct PetView: View {
    
    @EnvironmentObject var viewRouter: ViewRouter

    var body: some View {
        Text(viewRouter.selectedPet!.name)
    }
}

import Foundation

struct Pet: Identifiable, Hashable {
    var name: String
    var id: String { name }

}


Solution

  • try this:

    @main
    struct TestListAppApp: App {
    @StateObject var viewRouter = ViewRouter()
        var body: some Scene {
            WindowGroup {
                ContentView().environmentObject(viewRouter)
            }
        }
    }
    struct PetView: View {
        @EnvironmentObject var viewRouter: ViewRouter
        
        var body: some View {
            if let pet = viewRouter.selectedPet {
                Text(pet.name)
            } else {
                EmptyView()
            }
        }
    }
    
    struct ContentView: View {
        @EnvironmentObject var viewRouter: ViewRouter
        
        var body: some View {
            NavigationView {
                List {
                    ForEach(viewRouter.pets) { pet in
                        NavigationLink(destination: PetView(),
                                       tag: pet,
                                       selection: $viewRouter.selectedPet,
                                       label: {
                            Text(pet.name)
                        })
                    }
                    Button("Go to first pet.") {
                        viewRouter.selectedPet = viewRouter.pets[0]
                    }
                }
            }
        }
    }