SwiftUI: Why is second alert not showing? - swiftui

In the following simple example, why is Alert 2 not showing up?
struct ContentView: View {
#State private var showingOtherButton = false
#State private var showingAlert1 = false
#State private var showingAlert2 = false
var body: some View {
Group {
if showingOtherButton {
Button("Show Alert 2") {
showingAlert2 = true
}
.alert(isPresented: $showingAlert2) {
print("Alert 2 should be shown")
return Alert(title: Text("Alert 2"), dismissButton: .default(Text("Ok")))
}
} else {
Button("Show other Button") {
self.showingOtherButton = true
}
Button("Show Alert 1") {
showingAlert1 = true
}
}
}
.alert(isPresented: $showingAlert1) {
Alert(title: Text("Alert 1"), dismissButton: .default(Text("OK")))
}
}
}
Placing the alert 1 modifier onto the "Show Alert 1" button directly makes it work, but I don't understand why.

Your second alert should go in the same place as the first - attached to the Group view, not to the Button:
Group {
if showingOtherButton {
Button("Show Alert 2") {
showingAlert2 = true
}
} else {
Button("Show other Button") {
self.showingOtherButton = true
}
Button("Show Alert 1") {
showingAlert1 = true
}
}
}
.alert(isPresented: $showingAlert1) {
Alert(title: Text("Alert 1"), dismissButton: .default(Text("OK")))
}
.alert(isPresented: $showingAlert2) {
print("Alert 2 should be shown")
return Alert(title: Text("Alert 2"), dismissButton: .default(Text("Ok")))
}

Related

Button with Label and Alert

I have this button
Button { }
label: {
Image(systemName: "info.circle")
}
and want to couple it with this alert
.alert(isPresented: $showAlert) {
Alert(title: Text("Impressum"), message: Text("?"), dismissButton: .default(Text("Okay")))
Using SwiftUI... It's not working.
You need to actually toggle the showAlert state.
Code:
struct ContentView: View {
#State private var showAlert = false
var body: some View {
Button {
showAlert.toggle()
} label: {
Image(systemName: "info.circle")
}
.alert(isPresented: $showAlert) {
Alert(title: Text("Impressum"), message: Text("?"), dismissButton: .default(Text("Okay")))
}
}
}
Result:

How can you show multiple alert dialogs, one after the other, in SwiftUI?

The following code shows a "Delete file" button. When the user presses it, a confirmation alert dialog appears. When the user presses "Delete" on that first dialog, I want to show a second alert dialog confirming that the file has been deleted. However, it never shows up, even though debugging the code confirmed that the second "return Alert..." statement is actually being executed as expected. Is there a way to make the second alert show up too?
import SwiftUI
enum alertShownType {
case alertNone, alertDeleteFile,alertFileDeleted
}
struct ContentView: View {
#State var showingAlert = false
#State var alertShown: alertShownType = alertShownType.alertNone
var body: some View {
Button(action: {
self.alertShown = alertShownType.alertDeleteFile
self.showingAlert = true
})
{
Text("Delete file")
}.padding(EdgeInsets(top: 0, leading: 0, bottom: 10, trailing:0))
.alert(isPresented: $showingAlert, content: {
if (alertShown == alertShownType.alertDeleteFile)
{
return Alert(title: Text("Delete file"),
message: Text("Are you sure?"),
primaryButton: .destructive(Text("Delete")) {
// Delete the file
....
// Show the next alert
alertShown = alertShownType.alertFileDeleted
showingAlert = true
},
secondaryButton: .cancel())
}
else // alertFileDeleted
{
return Alert(title: Text("File deleted"), message:
Text("Done!"),
dismissButton: .default(Text("OK")))
}
})
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
You just need
public func alert<Item>(item: Binding<Item?>, content: (Item) -> Alert)
Not required #State var showingAlert = false flag.
Setup you code like this
enum alertShownType : Identifiable {
case alertNone,
alertDeleteFile,
alertFileDeleted
var id : Int { get {
hashValue
}}
}
struct ContentViewAlerts: View {
#State var alertShown: alertShownType?
var body: some View {
Button(action: {
self.alertShown = alertShownType.alertDeleteFile
})
{
Text("Delete file")
}.padding(EdgeInsets(top: 0, leading: 0, bottom: 10, trailing:0))
.alert(item: $alertShown, content: { alertType in
if (alertShown == alertShownType.alertDeleteFile)
{
return Alert(title: Text("Delete file"),
message: Text("Are you sure?"),
primaryButton: .destructive(Text("Delete")) {
// Delete the file
// ....
// Show the next alert
alertShown = alertShownType.alertFileDeleted
},
secondaryButton: .cancel())
}
else // alertFileDeleted
{
return Alert(title: Text("File deleted"), message:
Text("Done!"),
dismissButton: .default(Text("OK")))
}
})
}
}

SwiftUI Alert How do I get it to work in a simple if statement?

This should be simple but I am hoping to display an alert when a condition is true.(see below) I have seen lots where you used a button to trigger an alert, but I just want an alert to trigger when a condition is met such as in a simple "If" statement. Which should appear as soon as the code is loaded.
import SwiftUI
struct ContentView: View {
#State private var showingAlert = false
var score = 3
var body: some View {
VStack{
if score == 3 {
showingAlert = true
} .alert(isPresented: $showingAlert) {
Alert(title: Text("Hello SwiftUI!"), message: Text("This is some detail message"), dismissButton: .default(Text("OK")))
}
}
}
You can check if your condition is true in the init() method of the view and then set the initial value of your showingAlert.
struct ContentView: View {
#State private var showingAlert = false
var score = 3
init()
{
//check if condition is true
if (true)
{
self._showingAlert = State(initialValue: true)
}
}
var body: some View {
VStack{
EmptyView()
} .alert(isPresented: self.$showingAlert) {
Alert(title: Text("Hello SwiftUI!"), message: Text("This is some detail message"), dismissButton: .default(Text("OK")))
}
}
}

SwiftUI - Button Action to Alert and take action

I am trying to send alert based on a condition, but the Navigation link is executing regardless of the condition. I was hoping for an intercept.
Goal:
If condition is not me then do not launch new view
New View is launching and then alert.
I am sure my code is incorrect, but I am unsure how I should achieve this
Thanks in advance.
var body: some View {
NavigationView {
VStack {
Button(action: {}) {
//NavigationLink(destination: secondView()) {
NavigationLink(destination: checkState()) {
Text("Add to Cart")
}.padding()
.font(.system(size: 14))
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(6)
}
}
}.padding()
} // End of the GetOrder Struct
struct GetdOrderView_Previews: PreviewProvider {
static var previews: some View {
GetdOrderView()
}
}
}
struct checkState: View {
#ObservedObject var calcCheck = MealOrder()
#State var showingAlert = false
#State var myToggle = false
var body: some View {
NavigationView {
VStack {
Button(action: {
//Enter Action here
if self.myToggle == true {
self.showingAlert = true
} else {
self.showingAlert = true
}
}) {
Text("This is a test")
}.padding()
.font(.system(size: 14))
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(6)
//Insert Alerts
.alert(isPresented: $showingAlert) {
if self.myToggle {
return Alert(title: Text("Showing Message"), message: Text("Cart is valid"), dismissButton: .default(Text("OK")))
} else {
return Alert(title: Text("Showing Alert"), message: Text("Cart Empty"), dismissButton: .default(Text("Cancel")))
}
}
}
}
}
}
struct secondView: View {
var body: some View {
VStack {
Text("This is the second test")
}
}
}
Try the following approach
#State var activateLink = false
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: checkState(), isActive: $activateLink) {
EmptyView()
}
Button(action: {
if _YOUR_CONDITION_HERE_ {
self.activateLink = true
}
}) {
Text("Add to Cart")
.padding()
.font(.system(size: 14))
.background(Color.red)
.foregroundColor(.white)
.cornerRadius(6)
}
}
.onAppear { self.activateLink = false }
}.padding()
}// End of the GetOrder Struct

ForEach(0...5,id: \.self) { n in --what is the scope of "n"?

See the following TestView. When I clicked "Button 5", I see the alert shows "Button 0 clicked".
struct TestView: View {
#State var showAlert = false
var body: some View {
VStack {
ForEach(0...5, id: \.self) { n in
Button(action: {
self.showAlert.toggle()
}) {
Text("Button \(n)")
}
.padding(20)
.border(Color.green, width: 4)
.padding(8)
.alert(isPresented: self.$showAlert) {
Alert(title: Text("Button \(n) clicked"))
}
}
}
}
}
Regardless of which button I click, the alert always show "Button 0 clicked". I was expecting each button should show its own button index. Wondering why is that?
I suspect this is happening because everything in your TestView re-renders while state variable changes. So your alert is displaying only for the first loop iteration. The decision is to change other variable, which should contain clicked button index:
struct TextView: View {
#State var showAlert = false
#State var clickedButtonIndex = 0
var body: some View {
VStack {
ForEach(0...5, id: \.self) { n in
Button(action: {
self.showAlert.toggle()
self.clickedButtonIndex = n
}) {
Text("Button \(n)")
}
.padding(20)
.border(Color.green, width: 4)
.padding(8)
.alert(isPresented: self.$showAlert) {
Alert(title: Text("Button \(self.clickedButtonIndex) clicked"))
}
}
}
}
}
And you'll have this result: