skip to Main Content

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


  1. Chosen as BEST ANSWER

    I ended up solving the issue by converting @State var item: RecipeStepModel in my view model to @Binding var item: RecipeStepModel

    struct CustomTextField : View {
    @Binding var item : RecipeStepModel
    
    var body : some View {
        Text(String(item.stepNumber) + ".")
        TextField("", text: $item.stepName)
    }
    

    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) to ForEach(recipeArray.indices, id: .self) :

     List {
                ForEach(recipeArray.indices, id: .self) { index in
                                HStack {
                                CustomTextField(item: $recipeArray[index]) //<--change made here
                                }
                    }.onDelete { (indexSet) in
                        recipeArray.remove(atOffsets: indexSet)
                    }
    

    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


  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search