How to pre-fill Form in SwiftUI

Viewed 568

i am currently working with Forms in SwiftUI. I am implementing a EditUser View and therefore am trying to pre-fill the Form with the previous Inputs

I am passing a User Object which contains all the relevant Data and using the initializer to update all of the input states.

struct EditUserView: View {
    
    let user: User?
    @Binding var showEditUserView: Bool
    
    @State private var gender: User.Gender = .notSet
    @State private var firstName: String = ""
    @State private var lastName: String = ""
    
    init(for user: User?, show: Binding<Bool>) {
        // First, update the Struct Properties with the given Values
        self.user = user
        self._showEditUserView = show
        
        // Second, if a User was given, update all Inputs with the given Values
        if let safeUser = user {
            gender = safeDoctor.gender
            firstName = safeDoctor.firstName
            lastName = safeDoctor.lastName
        }
    }

    // Some other Code

    Picker(selection: $gender, label: Text("Gender")) {
        ForEach(User.Gender.allCases, id: \.self) { gender in
            if gender != .notSet { Text(gender.string).tag(gender) }
        }
    }
    HStack {
        TextField("FirstName", text: $firstName)
        Divider()
        TextField("LastName", text: $lastName)
    }

When creating a new instance of EditUserView while providing a User (NOT nil), the input fields are not getting updated with the provided values.

Can anyone spot a reason for this not to be working?

Thanks for your help.

3 Answers

States should be initialized differently - not by value, but as State.

Here is fixed variant:

struct EditUserView: View {
    
    let user: User?
    @Binding var showEditUserView: Bool
    
    @State private var gender: User.Gender    // here declare only
    @State private var firstName: String
    @State private var lastName: String
    
    init(for user: User?, show: Binding<Bool>) {
        // First, update the Struct Properties with the given Values
        self.user = user
        self._showEditUserView = show
        
        // Second, if a User was given, update all Inputs with the given Values
        self._gender = State(initialValue: user.gender ?? .notSet)
        self._firstName = State(initialValue: user.firstName ?? "")
        self._lastName = State(initialValue: user.lastName ?? "")
    }

    // ... other code

Put your code that sets your @State variables in an .onAppear() modifier for your EditUserView instead of the initializer. That should do it.

In functional programming , we can track the changes in Struct, so that using Struct as model ( User ) is the best way.

then you can use like below.

struct ContentView: View {
    
    @State var user: User
    var body: some View {
        VStack {
            TextField("FirstName", text: $user.firstName)
            Divider()
            TextField("LastName", text: $user.lastName)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(user: User(firstName: "christophriepe", lastName: "last name"))
    }
}

struct User {
    var firstName: String
    var lastName: String
}
Related