1

I have a DataManager in which I have the following delete func:

  func deleteValue(index: Int) {
        storage.remove(at: index)
        save()
    }

And then in another view I have all my values into a Form. I wouldn't like to use the .onDelete because I would like to have an Alert that lets the user decide if he/she really wants to delete the value, but by doing this I must insert the index. How do I do this? Here's the code:

@State var showAlertDelete = false

var dm : DataManager

var deleteButton : some View {
    Button(action: {
        showAlertDelete = true
    }) { Text("Delete").foregroundColor(Color.red)
    }.alert(isPresented: $showAlertDelete, content: {
        deleteValueAlert
    })
}

func deleteValue(at offset: IndexSet) {
    guard let newIndex = Array(offset).first else { return }
    dm.deleteValue(index: newIndex)
}

var deleteValueAlert : Alert {
    Alert(title: Text("Are you sure you want to delete this?"), primaryButton: Alert.Button.default(Text("Yes")){ deleteValue //Here it says that I must add the init with the index }, secondaryButton: Alert.Button.cancel(Text("No")))
}

How can I solve this? Thanks to everyone!

0

2 Answers 2

4

You can use .onDelete by also presenting an Alert when triggered, simply add:

@State private var showAlert = false    
@State private var indexSetToDelete: IndexSet?

And then in your .onDelete method:

.onDelete { (indexSet) in
     self.showAlert = true
     self.indexSetToDelete = indexSet
 }

Last step would be to add the Alert in your view body where you can call your delete method:

.alert(isPresented: $showAlert) {
    Alert(title: Text("Confirm Deletion"),
        message: Text("Are you sure you want to delete xxx?"),
        primaryButton: .destructive(Text("Delete")) {
           self.deleteValue(indexSet: self.indexSetToDelete!) //call delete method
        },
        secondaryButton: .cancel())
}
Sign up to request clarification or add additional context in comments.

2 Comments

fantastic solution guys
This solution has a problem that we see the contact deletion animation- then it pops back into existence as we are asked to confirm, then if we confirm it vanishes. Is there any way to hide the deleted contact until we know whether or not to delete it? (Only solution I can think of is to delete the item from the list temporarily, and restore it if the user cancels?)
3

This solution is very similar to knorrbert's, however it addresses @Peter Johnson's concern about the deleted row disappearing, reappearing when the alert is presented, and disappearing again when the user confirms the deletion. If you don't use .onDelete and instead use .swipeActions without the .destructive role - manually adding in .tint(.red) so it looks like a swipe-to-delete action - you can achieve the same effect without causing the list row to disappear, immediately reappear with the alert, and then disappear a second time.

@State private var showAlert = false
@State private var itemToDelete: ItemModel?

var body: some View {
    NavigationStack {
        List {
            ForEach(items) { item in
                NavigationLink {
                    Text(item.name)
                } label: {
                    Text(item.name)
                }
                .swipeActions(allowsFullSwipe: false) {
                    Button() {
                        self.itemToDelete = items.first(where: {$0.id == item.id})
                        showAlert = true
                    } label: {
                        Label("Delete", systemImage: "trash.fill")
                    }
                    .tint(.red)
                } // End of .swipeActions()
            } // End of ForEach
        } // End of List
        .alert(isPresented: $showAlert) {
            Alert(title: Text("Confirm Deletion"),
                  message: Text("Are you sure you want to delete \(itemToDelete!.name)?"),
                primaryButton: .destructive(Text("Delete")) {
                    deleteItem(deleteThisOne: itemToDelete!) //call delete method
                },
                secondaryButton: .cancel())
        } // End of .alert
    } // End of NavigationStack
} // End of body

mutating func deleteItem(deleteThisOne: ItemModel) {
    if let index = items.firstIndex(where: {$0.id == deleteThisOne.id}) {
        items.remove(at: index)
    }
}

1 Comment

this is awesome! Anyway you figure out how to do the animation effect to by any chance?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.