Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best Way to Update/Edit an Array Element in SwiftUI

I have an array of identifiable Training elements. Each Training element only has two properties, name and isRequired.

What is the most straight-forward (Swiftyiest) way to update the existing values of an array element to new edited values... the edited values will then later be submitted to the database.

Is it possible to set the state in the EditTraining View (Child) to the passed in (Parent) values and then edit the state in the child view?

I've been stuck on this longer than I'll ever admit.

Thank you very much for any help at all!

Here is the code:

import SwiftUI

struct Training: Identifiable {
    let id: String
    let trainingName: String
    let isRequired: Bool
}

class GetTrainings: ObservableObject {
    @Published var items = [Training]()

    init() {
        self.items = [
            Training(id: "ttt1", trainingName: "Safety", isRequired: true),
            Training(id: "ttt2", trainingName: "Administrative", isRequired: false),
            Training(id: "ttt3", trainingName: "Computer", isRequired: true),
            Training(id: "ttt4", trainingName: "People", isRequired: true),
            Training(id: "ttt5", trainingName: "Managerial", isRequired: true),
        ]
    }
}

struct TrainingList: View {

    @ObservedObject var trainings = GetTrainings()

    var body: some View {
        NavigationView {
            VStack {
                List {

                    ForEach(trainings.items) { training in

                        HStack {
                            NavigationLink(destination: TrainingView(training: training)) {
                                Text("\(training.trainingName)")
                            }
                        }
                    }

                }
            }.navigationBarTitle("Training List")
        }
    }
}

struct TrainingView: View {

    var training: Training

    var body: some View {

        VStack {

            Text("\(training.trainingName)").font(.body)
            Text("\(training.isRequired == true ? "Required Training" : "Training Not Required")")

            HStack {
                NavigationLink(destination: EditTraining(training: training)) {
                    Text("Edit Training Details")
                }
            }
        }.navigationBarTitle("\(training.trainingName) Page", displayMode: .inline)

    }
}

struct EditTraining: View {

    var training: Training

    // Can I set the state values to the passed in values ???
    @State private var newName: String = ""
    @State private var isRequiredTraining: Bool = false
    //@Binding var name: String = training.trainingName ????

    private func submitData() {

        let newName = self.newName
        let newBoolVal = self.isRequiredTraining

        print("Firebase Sync Id is :\(training.id) Text: \(newName) and Bool: \(newBoolVal)")

    }

    var body: some View {
        VStack {
            Form {
                Section (header: Text("Edit"))  {

                    Text("\(training.trainingName)")
                    /* TextField should Populate With passed In Training Name Here*/
                    TextField("New Name", text: self.$newName)
                    Toggle(isOn: self.$isRequiredTraining) {
                        Text("Is Required")
                    }
                }

                Section {

                    Button(action: {
                        self.submitData()
                    }) {
                        Text("Submit")
                    }

                }
            }
        }.navigationBarTitle("Edit Training Page", displayMode: .inline)
    }
}

struct ContentView: View {

    var body: some View {

        VStack {

            TrainingList()

        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
like image 341
Clay_F Avatar asked May 30 '20 17:05

Clay_F


People also ask

How do you update an element in an array?

To update a particular item in an array, there are 2 ways, i.e., either by its value or by its index. Here, we will use the concept of the Property accessors method that is used to access the properties of an object using the bracket notation. Approach: In the first example, the element is updated by its value.

How do you update an array in Swift?

Swift Array – Replace Element To replace an element with another value in Swift Array, get the index of the match of the required element to replace, and assign new value to the array using the subscript.

Can you modify an array?

Given an array, we need to modify values of this array in such a way that sum of absolute differences between two consecutive elements is maximized. If the value of an array element is X, then we can change it to either 1 or X.

How do you update a number in an array?

To update all the elements of an array, call the forEach() method on the array, passing it a function. The function gets called for each element in the array and allows us to update the array's values.


1 Answers

This is the case when as I see it is more preferable to use ObservableObject for models, because it allows to pass by reference model object deep into hierarchy and keep it up to date during workflow.

Here is a solution. Tested with Xcode 11.4 / iOS 13.4

demo

class Training: ObservableObject, Identifiable {
    let id: String
    @Published var trainingName: String
    @Published var isRequired: Bool

    init(id: String, trainingName: String, isRequired: Bool) {
        self.id = id
        self.trainingName = trainingName
        self.isRequired = isRequired
    }
}

class GetTrainings: ObservableObject {
    @Published var items = [Training]()

    init() {
        self.items = [
            Training(id: "ttt1", trainingName: "Safety", isRequired: true),
            Training(id: "ttt2", trainingName: "Administrative", isRequired: false),
            Training(id: "ttt3", trainingName: "Computer", isRequired: true),
            Training(id: "ttt4", trainingName: "People", isRequired: true),
            Training(id: "ttt5", trainingName: "Managerial", isRequired: true),
        ]
    }
}

struct TrainingList: View {

    @ObservedObject var trainings = GetTrainings()

    var body: some View {
        NavigationView {
            VStack {
                List {

                    ForEach(trainings.items) { training in

                        HStack {
                            NavigationLink(destination: TrainingView(training: training)) {
                                Text("\(training.trainingName)")
                            }
                        }
                    }

                }
            }.navigationBarTitle("Training List")
            .onAppear {
                self.trainings.objectWillChange.send() // refresh
            }
        }
    }
}

struct TrainingView: View {

    @ObservedObject var training: Training

    var body: some View {

        VStack {

            Text("\(training.trainingName)").font(.body)
            Text("\(training.isRequired == true ? "Required Training" : "Training Not Required")")

            HStack {
                NavigationLink(destination: EditTraining(training: training)) {
                    Text("Edit Training Details")
                }
            }
        }.navigationBarTitle("\(training.trainingName) Page", displayMode: .inline)

    }
}

struct EditTraining: View {

    @ObservedObject var training: Training

    @State private var newName: String
    @State private var isRequiredTraining: Bool

    init(training: Training) {
        self.training = training
        self._newName = State(initialValue: training.trainingName)
        self._isRequiredTraining = State(initialValue: training.isRequired)
    }

    private func submitData() {

        let newName = self.newName
        let newBoolVal = self.isRequiredTraining

        print("Firebase Sync Id is :\(training.id) Text: \(newName) and Bool: \(newBoolVal)")

        self.training.trainingName = newName
        self.training.isRequired = newBoolVal
    }

    var body: some View {
        VStack {
            Form {
                Section (header: Text("Edit"))  {

                    Text("\(training.trainingName)")
                    /* TextField should Populate With passed In Training Name Here*/
                    TextField("New Name", text: self.$newName)
                    Toggle(isOn: self.$isRequiredTraining) {
                        Text("Is Required")
                    }
                }

                Section {

                    Button(action: {
                        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),
                            to:nil, from:nil, for:nil)
                        self.submitData()
                    }) {
                        Text("Submit")
                    }

                }
            }
        }.navigationBarTitle("Edit Training Page", displayMode: .inline)
    }
}

backup

like image 52
Asperi Avatar answered Sep 21 '22 17:09

Asperi