I am having trouble updating values in an array that are displayed via a for each loop. These values are displayed in a text field.
The code in question
struct EditItemView: View {
let entity: RecipeEntity
@StateObject var viewModel = ViewModelEdit()
@State var imageToUpload: Data
@StateObject var vm = CoreDataRelationshipViewModel()
@Environment(.presentationMode) var presentationMode
@State var stepInfo: String = ""
@State var textFieldCount: Int = 1
@State var stepNumber: [Int]
@State var recipeName: String = ""
@State var recipeArray: [RecipeStepModel]
var body: some View {
//some code between here and the problem code
List {
ForEach(recipeArray, id: .id) { index in
HStack {
CustomTextField(item: index)
}
}.onDelete { (indexSet) in
recipeArray.remove(atOffsets: indexSet)
}
CustomTextField I am using that allows me to pass my Identifiable model into a foreach. This can be seen referenced in the for each above as CustomTextField(item: index)
struct CustomTextField : View {
@State var item : RecipeStepModel
var body : some View {
Text(String(item.stepNumber) + ".")
TextField("", text: $item.stepName)
}
}
Lastly, here is the model for the array referenced in the last @State variable declared @State var recipeArray: [RecipeStepModel]
:
struct RecipeStepModel: Identifiable {
var id = UUID()
var stepName: String
var stepNumber: Int
}
The Question
How can I make a change to a textfield in a foreach loop and have its value in @State var recipeArray: [RecipeStepModel]
be updated accordingly? For example, I edit the first TextField in the for each loop – how can I update index 0 in the array with its new value?
Additional Information
I posted a similar question the other day. I was able to get it working with .indices in the for each loop. The version of the question asked here is an attempt at restructuring my code using MVVM. Previous question and answer can be found here – I hope this helps!
2
Answers
I ended up solving the issue by converting
@State var item: RecipeStepModel
in my view model to@Binding var item: RecipeStepModel
Once this change was made, I had to alter the code in my ForEach to pass a binding to the CustomTextField view model. Additionally, I had to change
ForEach(recipeArray, id: .id)
toForEach(recipeArray.indices, id: .self)
:I am now able to both successfully delete items from the list, and update items in the array simply by changing the value in the appropriate TextField
You need to follow a architecture like MVVM. Make a model where you have your struct RecipeStepModel and then make a seperate ViewModel to add and delete recipes in your array. You should study the Combine framework in SwiftUI, it is used to get input from textfield and then store it in an array.
Check this tutorial from Peter Freise https://github.com/peterfriese/MakeItSo/tree/firebase-combine/final/MakeItSo/MakeItSo for reference.