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, whenselectDelete
is 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
selectedUsers
variable 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
selectedUser
in 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)