How to Use Navigation in Alert Using Swiftui

How can I use Navigation in alert using SwiftUI

I simplified your code snapshot for demo, but think the idea would be clear

struct TestNavigationFromAlert: View {

@State private var showUnpairAlert: Bool = false
@State private var activateLink: Bool = false

var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("Your Onboarding page"), isActive: $activateLink,
label: { EmptyView() })

// DEMO BUTTON - REMOVE IT
Button(action: { self.showUnpairAlert = true }) { Text("Alert") }

// YOUR CODE IS HERE
}
.alert(isPresented: $showUnpairAlert) {
Alert(title: Text("Unpair from \(checkForDeviceInformation())"), message: Text("Do you want to unpair the current pod?"), primaryButton: .destructive(Text("Unpair")) {
self.unpairAndSetDefaultDeviceInformation()
}, secondaryButton: .cancel())
}
}
}

func checkForDeviceInformation() -> String {
// YOUR CODE IS HERE
return "Stub information"
}

func unpairAndSetDefaultDeviceInformation() {
// YOUR CODE IS HERE
DispatchQueue.main.async {
self.activateLink = true
}
}
}

Navigating back to main menu View in SwiftUI with Alert Button

To achieve what you are expecting, you actually need to add the NavigationView inside ContentView, if that's your main view. Because you navigate from ContentView to GameView, and what you are asking here is how to navigate back.

Applying the concept above, you can just dismiss GameView to go back to the in view.

Here is a sample code to achieve that:

Example of main view:

struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink {
GameView()

// This is how you hide the "<Back" button, so the user
// can navigate back only when tapping the alert
.navigationBarHidden(true)
} label: {
Text("Go to game view")
}
}
}
}

Example of game view:

struct GameView: View {

// This variable will dismiss the view
@Environment(\.presentationMode) var presentationMode

@State private var questionCounter = 1
@State var userAnswer = ""
@State private var alertTitle = ""
@State private var gameOver = false

// No need to use this variable
// @State private var menuNavigation = false

var body: some View {

// No need to have a NavigationView
// NavigationView {

// ZStack has no function apparently...
// ZStack{

// No need to have a NavigationLink
// NavigationLink(destination:ContentView(), isActive: $menuNavigation){
// Text("")
//}
VStack {

Text("Give the answer")
TextField("Give it", text: $userAnswer)

Button("Submit", action: answerQuestion)
}
.alert(isPresented: $gameOver) {
Alert(title: Text(alertTitle),
dismissButton: Alert.Button.default(
Text("Back to menu"), action: {

// This is how you go back to ContentView
presentationMode.wrappedValue.dismiss()
}
)
)
}
}


func answerQuestion() {

questionCounter += 1

if questionCounter == 2 {
gameOver.toggle()
alertTitle = "Game Over"
}
}
}

SwiftUi: Navigating to a secondary page through Button Alert Confirmation

To get the Back button you need a NavigationLink vs a popover. You can just "hide" the NavigationLink next to your Button

import SwiftUI

struct ConfirmNavView: View {
@State var txtField1 : String = ""
@State var txtField2: String = ""
@State var txtField3: String = ""
@State var txtField4: String = ""
@State var txtField5 : String = ""

@State private var showingAlert = false
@State private var showingView = false

var body: some View {
NavigationView{
HStack{
Button(action: {
self.showingAlert = true
}) {
Text("Submit")
.alert(isPresented:$showingAlert) {
Alert(title: Text("Would you like to go to second screen?"), message: Text("The second screen will pass all data from the first screen."), primaryButton:.destructive(Text("Continue")){
self.showingView = true
}, secondaryButton: .cancel(Text("Cancel")))
}
}

NavigationLink("View2", destination: View2(txtField1: self.$txtField1,
txtField2: self.$txtField2,
txtField3: self.$txtField3,
txtField4: self.$txtField4,
txtField5: self.$txtField5), isActive: $showingView).hidden().frame(width: 0, height: 0)
}
}

}
}
struct View2: View {
@Binding var txtField1 : String
@Binding var txtField2: String
@Binding var txtField3: String
@Binding var txtField4: String
@Binding var txtField5 : String
var body: some View {
VStack{
TextField("txtField1", text: $txtField1)
TextField("txtField2", text:$txtField2)
TextField("txtField3", text:$txtField3)
TextField("txtField4", text:$txtField4)
TextField("txtField5", text:$txtField5)
}
}
}
struct ConfirmNavView_Previews: PreviewProvider {
static var previews: some View {
ConfirmNavView()
}
}

Why is NavigationLink not working inside of a SwiftUI alert?

Because NavigationLink needs to be inside of a hierarchy using NavigationView. An alert is a modal presented outside of that structure.

If you would like to programmatically navigate, you can use the isActive property of a NavigationLink within the NavigationView hierarchy.

struct ContentView : View {
@State private var alertIsPresented = false
@State private var navLinkActive = false

var body: some View {
NavigationView {
VStack{
Button("Present alert") {
alertIsPresented = true
}
.alert("End of available content", isPresented: $alertIsPresented) {
Button("Navigate") {
navLinkActive = true
}
}
NavigationLink(isActive: $navLinkActive, destination: { SearchView() }, label: {
EmptyView()
})
}
}
}
}

struct SearchView : View {
var body: some View {
Text("Search")
}
}

How to navigate using button with condition check in SwiftUI

You can do something like this:

    NavigationView {
VStack {
NavigationLink(destination: Dashboard(userName: self.userId, password: self.password), isActive: $showDashboard) {
Text("")
}
Button(action: {
if self.userId.isEmpty || self.password.isEmpty {
self.isAlert = true
} else {
self.showDashboard = true
}
}) {
Text("Submit")
.foregroundColor(.green)
.font(.system(size: 22))

}
}
}

A thing to remember is that a NavigationLink is a button itself and when pressed it navigate to the destinationView, the isActive parameter is a way to force that to happen (without the user clicking the NavigationLink). As of now I'm not sure how to embed logic into NavigationLinks.

Hope this helps :)

EDIT:

Another thing you can do is the following:

NavigationLink(destination:Dashboard(userName: self.userId, password: self.password)) {
Text("Submit")
}.disabled(self.userId.isEmpty || self.password.isEmpty )

This would disable the NavigationLink until both input fields are not empty.



Related Topics



Leave a reply



Submit