I have a problem in my SwiftUI project, and I am trying to use alert dialog to delete an item in a list, but when use the .alert, wrong item gets deleted. I am still do not know what I missed?
Here is my code:
struct CustomView: View {
@State private var selectedUsers: CustomModel?
@State var users: [CustomModel]
@State private var selectDelete = false
var body: some View {
ScrollView(.vertical, showsIndicators: false, content: {
VStack(content: {
ForEach(users){ user in
CustomRowView(user: user)
.contextMenu {
Button(action: {
self.delete(item: data)
}) {
Text("remove")
}
}
.onTapGesture {
selectedUsers = user
}
.alert(isPresented: $selectDelete) {
Alert(title: Text("title"),
message: Text("message"),
primaryButton: .destructive(Text("Delete")) {
self.delete(item: user)
},
secondaryButton: .cancel()
)
}
.onDelete { (indexSet) in
self.users.remove(atOffsets: indexSet)
}
}
})
})
}
private func delete(item user: CustomModel) {
if let index = users.firstIndex(where: { $0.id == user.id }) {
users.remove(at: index)
}
}
}
model:
struct CustomModel: Identifiable{
var id = UUID().uuidString
var name: String
}
var users = [
CustomModel(name: "david"),
CustomModel(name: "marry"),
CustomModel(name: "henry"),
CustomModel(name: "nadi"), ]
CodePudding user response:
There are 2 problems in your code that are creating the unexpected behaviour:
When you iterate through the user with
ForEach, you are attaching one.alert()modifier to each single instance. This means, whenselectDeleteis set totrue, all of the instances try to show an alert, but only one will. Which one? Who knows, but that instance will be deleted.You have a nice
selectedUsersvariable that changes when you tap on it. But you are deleting theuser, notselectedUser.
How you can fix your code to work with .alert() in 3 steps:
- if you don't need to perform any task with the tap gesture, just delete it and change the
selectedUserin your context menu:
.contextMenu {
Button(action: {
selectedUsers = user // Change here then delete
self.delete(item: data)
}) {
Text("remove") }}
// Forget about it...
//.onTapGesture {
// selectedUsers = user
//}
- attach your alert to the top-most level of your view (at the bottom):
ScrollView {
...
}
.alert(isPresented: $selectDelete) {
...
}
- delete
selectedUser, notuser:
self.delete(item: selectedUser)
