I'm building an app where you have cards for each study item that is stored in an array and what I wanted to do was to allow the user to swipe left on a study item and allow them to delete the card.
Each card has two bindings to allow user to edit two textFields, so I have to use indices on the ForEach to specify the textField that is being edited, because when I don't use indices and have the foreach parameter as a binding and iterate through each item, when the user edits a specify textField, he can only type in one letter and it skips to the next textField.
In this case, present below, I am able to swipe left on each card("Section") and delete it when it's empty but when I start typing on individual textFields with different texts and delete it, it crashes.
Any help will be appreciated!
Here is the foreach loop that is in a subview of another view
@ObservedObject var currentStudySet: HomeViewModel
ForEach(currentStudySet.studySet.studyItem.indices, id: \.self) { index in
Section {
VStack {
TextField("Title", text: $currentStudySet.studySet.studyItem[index].itemTitle)
.padding(5)
.frame(maxWidth: .infinity, alignment: .leading)
.background(backgroundColor)
.cornerRadius(10)
TextField("Description", text: $currentStudySet.studySet.studyItem[index].itemDescription)
.padding(5)
.frame(maxWidth: .infinity, alignment: .leading)
.background(backgroundColor)
.cornerRadius(10)
}
.frame(maxWidth: .infinity)
}
}
.onDelete(perform: { (item) in
currentStudySet.studySet.studyItem.remove(atOffsets: item)
})
The view model has studySet but I won't put it for legibility purposes but here is the StudyModel that is "studySet"
struct StudyModel: Hashable{
var title: String = ""
var days = ["One day", "Two days", "Three days", "Four days", "Five days", "Six days", "Seven days"]
var studyGoals = "One day"
var studyItem: [StudyItemModel] = []
}
Here is the studyItemModel which is the studyItem array in StudyModel
struct StudyItemModel: Hashable{
var itemTitle: String = ""
var itemDescription: String = ""
}
CodePudding user response:
You can avoid using the index by doing the model conforms to Identifiable
, this is the way the ForEach
is meant to be use in SwiftUI atleast
import Foundation
import SwiftUI
struct fortest: View {
@ObservedObject var currentStudySet: HomeViewModel = HomeViewModel()
var body: some View {
List {
ForEach($currentStudySet.studySet.studyItem) { $studyItem in
Section {
VStack {
TextField("Title", text: $studyItem.itemTitle)
.padding(5)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.gray)
.cornerRadius(10)
TextField("Description", text: $studyItem.itemDescription)
.padding(5)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.gray)
.cornerRadius(10)
}
.frame(maxWidth: .infinity)
}
}
.onDelete(perform: { (item) in
currentStudySet.studySet.studyItem.remove(atOffsets: item)
})
}
}
}
class HomeViewModel: ObservableObject {
@Published var studySet: StudyModel = StudyModel()
}
struct StudyModel: Hashable{
var title: String = ""
var days = ["One day", "Two days", "Three days", "Four days", "Five days", "Six days", "Seven days"]
var studyGoals = "One day"
var studyItem: [StudyItemModel] = [StudyItemModel(itemTitle: "test 1", itemDescription: "hello"), StudyItemModel(itemTitle: "test 2", itemDescription: "hello"), StudyItemModel(itemTitle: "test 3", itemDescription: "hello")]
}
struct StudyItemModel: Hashable, Identifiable{
let id = UUID()
var itemTitle: String = ""
var itemDescription: String = ""
}