Amplify SwiftUI Authenticator UI, how to bind input field array to TextField

41 Views Asked by At

I am writing CustomSignUpView with Authenticator UI component in SwiftUI.

Can anyone give me an example of how to bind the PhoneNumber or Email fields to my TextField?

I tried the following but doesn't work

struct LoginScreen: View {
    var body: some View {
        Authenticator(
            signUpContent: { state in
                CustomSignUpView(state: state)
            }
        ) { _ in }
    }
}
struct CustomSignUpView: View {
   @ObservedObject var state: SignUpState
   var body: some View {
      TextField("number", text: $state.fields[0].value)
   }
}
2

There are 2 best solutions below

0
Salim On BEST ANSWER

I got the clean solution from Amplify team,

struct CustomSignUpView: View {
    @ObservedObject var state: SignUpState
    
    var body: some View {
        VStack {
            ForEach(state.fields, id: \.self) { field in
                CustomField(field)
            }

            Button("Sign Up") {
                Task {
                    try? await state.signUp()
                }
            }
        }
    }
}

struct CustomField: View {
    @ObservedObject private var signUpField: SignUpState.Field
    
    init(_ signUpField: SignUpState.Field) {
        self.signUpField = signUpField
    }
    
    var body: some View {
        /// Display the field accordingly, for example:
        switch signUpField.field.attributeType {
        case .username:
            TextField("Username", text: $signUpField.value)
        case .password:
            SecureField("Password", text: $signUpField.value)
        case .passwordConfirmation:
            SecureField("Confirm password", text: $signUpField.value)
        case .phoneNumber:
            TextField("Phone Number", text: $signUpField.value)
        case .email:
            TextField("Email", text: $signUpField.value)
        /// ... etc
        }
    }
}
1
Bilal Bakhrom On

In general, you should bind a TextField to a specific property, such as @State, rather than directly to an element in an array like $state.fields[0].value. To address this, you can add a new property to your SignUpState that allows you to directly access the email or phone number field based on a certain condition.

Here's how you can modify your CustomSignUpView to achieve this:

struct CustomSignUpView: View {
    @ObservedObject var state: SignUpState
    
    var body: some View {
        VStack {
            if state.isEmailSignUp {
                TextField("Email", text: $state.email)
            } else {
                TextField("Phone Number", text: $state.phoneNumber)
            }
        }
    }
}

class SignUpState: ObservableObject {
    /// For toggling between email and phone number
    @Published var isEmailSignUp: Bool = true 
    @Published var email: String = ""
    @Published var phoneNumber: String = ""
}