简体   繁体   中英

Why does Text disappear when i click submit?

When I type in my EditText view to fill out all the required information and then click submit. Everything I typed disappears. I want this text to remain. I am guessing there is something wrong with my @State objects but cannot figure out what.

SignUpViewModel

class SignUpViewModel : ObservableObject {

    @Published
    var error: String? = nil

    @Published
    var goHome: Bool = false

    @Published
    var goToLogin: Bool = false

    func onGoToLoginClicked() {
        self.goToLogin = true
    }

    func signUp(firstName: String, lastName: String, email: String, birthday: String, phoneNumber: String, password: String, confirmPassword: String) {
        if (firstName.count < 3) {
            error = "Please enter first name"
            return
        }
        if (lastName.count < 3) {
            error = "Please enter last name"
            return
        }
        if (!email.isEmail()) {
            error = "Pleaes enter valid email"
            return
        }
        if (birthday.isEmpty) {
            error = "Pleae enter valid birthday"
            return
        }
        if (!phoneNumber.isDigits) {
            error = "Please enter valid phone number"
            return
        }
        if (password.count < 8) {
            error = "Please enter a password that is at least 8 characters long"
        }
        if (password != confirmPassword) {
            error = "Password do not match"
        }
        Auth.auth().createUser(withEmail: email, password: password, completion: { authResult, error in
            if authResult != nil {
                self.goHome = true
            } else {
                self.error = error?.localizedDescription
            }
        })
    }
}

SignUp View

struct SignUpScreen: View {

    @State
    var firstName: String = ""
    @State
    var lastName: String = ""
    @State
    var birthday: String = ""
    @State
    var number: String = ""
    @State
    var email: String = ""
    @State
    var password: String = ""
    @State
    var confirmPassword: String = ""

    @EnvironmentObject
    var viewModel: SignUpViewModel


    var body: some View {
        ZStack {
            VStack {
                VClearBackground()
                Spacer()
            }
            ScrollView {
                VStack(alignment: .leading) {
                    Group {
                        PreHeaderText(header: "Get Started")
                            .alignmentGuide(.leading, computeValue: { d in
                                d[.leading]
                            })
                            .padding(EdgeInsets.init(top: 32, leading: 0, bottom: 0, trailing: 0))
                        HeaderText(header: "Create Account")
                        EditText(hint: "Huey", text: $firstName, label: "FIRST NAME", textContentType: UITextContentType.name)
                        EditText(hint: "Freeman", text: $lastName, label: "LAST NAME", textContentType: UITextContentType.name)
                        EditText(hint: "04-19-1994", text: $birthday, label: "BIRTHDAY")
                        EditText(hint: "(281) 456-7890)", text: $number, label: "MOBILE NUMBER", textContentType: UITextContentType.telephoneNumber, keyboardType: UIKeyboardType.phonePad)
                        EditText(hint: "email@exmaple.com", text: $email, label: "EMAIL", textContentType: UITextContentType.emailAddress)
                        EditText(hint: "********", text: $password, label: "PASSWORD", textContentType: UITextContentType.newPassword)
                        EditText(hint: "********", text: $confirmPassword, label: "CONFIRM PASSWORD", textContentType: UITextContentType.newPassword)
                    }
                    Group {
                        if self.viewModel.error != nil {
                            HStack {
                                Spacer()
                                Text(viewModel.error ?? "")
                                    .foregroundColor(ColorTheme.error.color)
                                Spacer()
                            }
                            .padding()
                        }
                        HStack {
                            Spacer()
                            VowerButton(text: "Submit") {
                                self.viewModel.signUp(firstName: self.firstName, lastName: self.lastName, email: self.email, birthday: self.birthday, phoneNumber: self.number, password: self.password, confirmPassword: self.confirmPassword)
                            }
                            Spacer()
                        }
                        .padding()

                        HStack {
                            Spacer()
                            NavigationLink(destination: LoginScreen(), isActive: $viewModel.goToLogin) {
                                CtaText(text: "Have an account?", cta: "Login") {
                                    self.viewModel.onGoToLoginClicked()
                                }
                            }
                            .padding()
                            Spacer()
                        }

                        Spacer()
                    }
                }
            }
            .padding(EdgeInsets.init(top: 16, leading: 16, bottom: 16, trailing: 16))
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
        }
        .background(LinearGradient(gradient: Gradient(colors: [.black, ColorTheme.brandPurple.color]), startPoint: .top, endPoint: .bottom))
        .edgesIgnoringSafeArea(.all)
    }
}

EditText View

struct EditText: View {

    var hint: String
    @Binding
    var text: String
    var label: String = ""
    var defaultValue =  ""
    var textContentType: UITextContentType? = .none
    var keyboardType: UIKeyboardType = .default

    private func initializeDefaultValue() {
        DispatchQueue.main.async {
            self.text = self.defaultValue
        }
    }

    var body: some View {
        initializeDefaultValue()
        return VStack(alignment: .leading) {
            Text(label).font(.system(size: 12)).bold()
                .foregroundColor(ColorTheme.text.color)
            HStack {
                TextField(hint, text: $text)
                .lineLimit(1)
                .textContentType(textContentType)
                .keyboardType(keyboardType)
                    .foregroundColor(ColorTheme.text.color)
            }
            Divider().background(Color(ColorTheme.brandBlue.value))
        }
        .padding(EdgeInsets.init(top: 12, leading: 0, bottom: 8, trailing: 0))
    }
}

预览

The problem code is in SignUpScreen :

@ObservedObject
var viewModel: SignUpViewModel = SignUpViewModel()

Whenever the view is re-evaluated, a new SignUpViewModel is created.

You can create the view model outside the view, and either pass it to the directly to the constructor, or inject it to the environment using environmentObject() .

To use an environment object instead, change the above declaration to:

@EnvironmentObject
var viewModel: SignUpViewModel

And then create your view like this:

var signUpViewModel = SignUpViewModel()

// ...

SignUpScreen()
    .environmentObject(signUpViewModel)

The problem is in your EditText view.

struct EditText: View {

    var hint: String
    @Binding
    var text: String
    var label: String = ""
    var defaultValue =  ""
    var textContentType: UITextContentType? = .none
    var keyboardType: UIKeyboardType = .default

    private func initializeDefaultValue() {
        DispatchQueue.main.async {
            self.text = self.defaultValue
        }
    }

    var body: some View {
        initializeDefaultValue()
        return VStack(alignment: .leading) {
            Text(label).font(.system(size: 12)).bold()
                .foregroundColor(ColorTheme.text.color)
            HStack {
                TextField(hint, text: $text)
                .lineLimit(1)
                .textContentType(textContentType)
                .keyboardType(keyboardType)
                    .foregroundColor(ColorTheme.text.color)
            }
            Divider().background(Color(ColorTheme.brandBlue.value))
        }
        .padding(EdgeInsets.init(top: 12, leading: 0, bottom: 8, trailing: 0))
    }
}

Specifically, it's in the body property. This is a computed property that is fetched by SwiftUI whenever the view is recomputed. In this case, this happens when the error property of the SignUpScreen view changes, as all the subviews are recomputed.

When this EditText view is recomputed, the initializeDefaultValue() function is called (it's the first line in the body property). This clears the text fields.

As for a solution, I'm not sure why you actually need the initializeDefaultValue function in here at all. It seems best suited for the ViewModel or some other location.


Also, just some other things that I saw:

func signUp(firstName: String, lastName: String, email: String, birthday: String, phoneNumber: String, password: String, confirmPassword: String) {
    if (firstName.count < 3) {
        error = "Please enter first name"
        return
    }
    if (lastName.count < 3) {
        error = "Please enter last name"
        return
    }
    if (!email.isEmail()) {
        error = "Pleaes enter valid email"
        return
    }
    if (birthday.isEmpty) {
        error = "Pleae enter valid birthday"
        return
    }
    if (!phoneNumber.isDigits) {
        error = "Please enter valid phone number"
        return
    }
    if (password.count < 8) {
        error = "Please enter a password that is at least 8 characters long"
    }
    if (password != confirmPassword) {
        error = "Password do not match"
    }
    Auth.auth().createUser(withEmail: email, password: password, completion: { authResult, error in
        if authResult != nil {
            self.goHome = true
        } else {
            self.error = error?.localizedDescription
        }
    })
}

This function returns early in all error cases except the last two — I believe this was a mistake.

if self.viewModel.error != nil {
    HStack {
        Spacer()
        Text(viewModel.error ?? "")
        .foregroundColor(ColorTheme.error.color)
        Spacer()
    }
    .padding()
}

This part of the SignUpScreen view should be able to be simplified to this:

if let err = self.viewModel.error {
    HStack {
        Spacer()
        Text(err)
        .foregroundColor(ColorTheme.error.color)
        Spacer()
    }
    .padding()
}

or, if if-let statements are not allowed in this case:

if self.viewModel.error != nil {
    HStack {
        Spacer()
        Text(viewModel.error!)
        .foregroundColor(ColorTheme.error.color)
        Spacer()
    }
    .padding()
}

as you know that the error is non- nil .


Hope all of this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM