3

How do I pass a Binding via the new .navigationDestination(for: , destination: )?

import SwiftUI

enum TestEnum: String, Hashable, CaseIterable {
    case first, second, third
}

struct ContentView: View {
    
    @State private var test: TestEnum = .first

    var body: some View {
        NavigationStack {
            VStack {
                NavigationLink(value: test, label: {
                    Text(test.rawValue)
                })
            }
            // This does not work, as it won't allow me to use $caze
            .navigationDestination(for: TestEnum.self, destination: { caze in
                SecondView(test: $caze)
            })
        }
    }
}

struct SecondView: View {
    
    @Environment(\.presentationMode) var presentationMode
    @Binding var test: TestEnum
    
    var body: some View {
        ForEach(TestEnum.allCases, id: \.self) { caze in
            Button(action: {
                test = caze
                presentationMode.wrappedValue.dismiss()
            }, label: {
                Text(caze.rawValue)
            })
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

In SwiftUI 3.0 I'd simply use:

NavigationLink(destination: SecondView(test: $test), label: {
   Text(test.rawValue)
})

Is this still the correct approach, as we cannot pass a Binding yet?

Not really interested in complex workarounds like using an EnvironmentObject and passing an index, as the SwiftUI 3.0 approach works fine.

However, if there is a proper way of passing a Binding via .navigationDestination(for: , destination: ) I'll happily use it.

Peanutsmasher
  • 220
  • 3
  • 13
  • 1
    I think there is nothing wrong with using `NavigationLink(destination: SecondView(test: $test), label: { Text(test.rawValue) })` with the `NavigationStack` instead of the `navigationDestination`. `NavigationView` is deprecated but not `NavigationLink(destination: ..)` – workingdog support Ukraine Nov 01 '22 at 01:39
  • 1
    There is no "proper" way that isn't what you are using now. `Binding` isn't `Hashable` – lorem ipsum Nov 01 '22 at 01:47
  • Supposing that one actually needs to use `.navigationDestination` with a `Binding`, for example in a programmatic navigation with bound properties... Is there a way to make `Binding` `Hashable`? – Jordan Niedzielski Nov 24 '22 at 18:14
  • The problem I found with using NavigationLink(destination:label:) is that it does not add the destination to the Navigation Stack path. – Jeff Zacharias Mar 18 '23 at 21:25

1 Answers1

-2

According to this doc:

https://developer.apple.com/documentation/charts/chart/navigationdestination(for:destination:)/

[WRONG: Where destination get passed from NavigationLink, but in the doc they use the NavigationLink("Mint", value: Color.mint) version of the NavigationLink. I don't know if this make any difference.

You are using the NavigationLink(value:label:)]

EDIT: I insist, after further investigation, that you are using the ViewModifier wrong.

Read the doc that I pointed above. The viewModifier signature is:

func navigationDestination<D, C>(
    for data: D.Type,
    destination: @escaping (D) -> C
) -> some View where D : Hashable, C : View

Note D is Hashable, not State

So, when you pass $caze you are not passing the @State var above, but the NavigationLink(value: test... that is not a @State wrapper. Is the generic D ... a single value, so $caze is not a Binding to the State.

You can pass normally $test, from that is a Binding to the State test. But the parameter inside the closure .navigationDestination( value in ... is not.

Allan Garcia
  • 550
  • 3
  • 16
  • Your answer is completely unrelated to the question. Also, NavigationLink("", value:) is the simplified version of NavigationLink(value:label:). The former has a simple Text and the latter can be a complex view for the NavigationLink’s label. – Peanutsmasher Nov 01 '22 at 00:55
  • Sorry for trying to answer you. I did my best. – Allan Garcia Nov 01 '22 at 19:56