Pull to refresh

SwiftUI & ChatGPT. The world is changing. Again

Level of difficultyEasy
Reading time4 min
Views2.9K

Fast app prototyping with SwiftUI & ChatGPT

Everything that follows from this point forward is my input prompts, followed by ChatCGP’s responses, complete with sample code in Swift.

Hey ChatGPT, can you make a SwiftUI registration form with name, address and city fields?

import SwiftUI

struct RegistrationForm: View {
    @State private var name: String = ""
    @State private var address: String = ""
    @State private var city: String = ""

    var body: some View {
        Form {
            TextField("Name", text: $name)
            TextField("Address", text: $address)
            TextField("City", text: $city)
        }
    }
}

The RegistrationForm struct conforms to the View protocol and defines a body property that returns a Form view. The Form view contains TextField views for each of the form fields, and the @State property wrapper is used to manage the state of each field.

Can you move the fields to a view model?

Move the form fields to a separate view model in order to better manage the state and logic of the form.

import SwiftUI

struct RegistrationForm: View {
    @ObservedObject var viewModel: RegistrationFormViewModel

    var body: some View {
        Form {
            TextField("Name", text: $viewModel.name)
            TextField("Address", text: $viewModel.address)
            TextField("City", text: $viewModel.city)
        }
    }
}

class RegistrationFormViewModel: ObservableObject {
    @Published var name: String = ""
    @Published var address: String = ""
    @Published var city: String = ""
}

The RegistrationForm struct has an @ObservedObject property that references an instance of the RegistrationFormViewModel class. This allows the RegistrationForm view to bind to the properties of the view model using the $ prefix, just as it did with the @State properties in the previous example.

The RegistrationFormViewModel class defines @Published properties for each of the form fields, which allows the view to be notified when the values of these properties change. This allows the view to update automatically when the user changes the form fields.

This approach helps to keep the view logic and state management separate from the view itself, making the code easier to understand and maintain.

What if I need to validate that none of the fields are empty?

If you need to validate that none of the fields in the form are empty, you can add a method to the RegistrationFormViewModel class that checks the values of the form fields and returns a Bool indicating whether the form is valid or not.

class RegistrationFormViewModel: ObservableObject {
    @Published var name: String = ""
    @Published var address: String = ""
    @Published var city: String = ""

    var isValid: Bool {
        return !name.isEmpty && !address.isEmpty && !city.isEmpty
    }
}

The isValid property uses the isEmpty property of each of the form fields to determine whether the form is valid or not. If all of the fields are not empty, the isValid property will return true, otherwise it will return false.

You can then use this property in the view to enable or disable a submit button or to display an error message if the form is not valid.

struct RegistrationForm: View {
    @ObservedObject var viewModel: RegistrationFormViewModel

    var body: some View {
        Form {
            TextField("Name", text: $viewModel.name)
            TextField("Address", text: $viewModel.address)
            TextField("City", text: $viewModel.city)

            if !viewModel.isValid {
                Text("All fields are required")
                    .foregroundColor(.red)
            }
        }
    }
}

The RegistrationForm view checks the value of the isValid property and, if the form is not valid, it displays an error message using a Text view. This allows the user to know which fields need to be filled out in order to make the form valid.

Can we add a Save button to that form?

Add a Save button to the form by using a Button view in the RegistrationForm struct.

struct RegistrationForm: View {
    @ObservedObject var viewModel: RegistrationFormViewModel

    var body: some View {
        Form {
            TextField("Name", text: $viewModel.name)
            TextField("Address", text: $viewModel.address)
            TextField("City", text: $viewModel.city)

            if !viewModel.isValid {
                Text("All fields are required")
                    .foregroundColor(.red)
            }

            Button(action: {
                // Save the form data here
            }) {
                Text("Save")
            }
            .disabled(!viewModel.isValid)
        }
    }
}

The RegistrationForm view includes a Button view with an action closure that is called when the button is tapped. This closure can be used to save the form data to a database or other storage location.

The Button view also has a disabled modifier that disables the button if the isValid property of the RegistrationFormViewModel is false. This ensures that the form must be filled out correctly before the user can save the data.

Can you create a User struct based on the form information?

A User struct that could be used to represent the data from the form:

struct User {
    var name: String
    var address: String
    var city: String
}

This User struct defines properties for each of the form fields, such as name, address and city. These properties can be used to store the values entered by the user in the form.

Create an instance of the User struct using the values from the form:

let user = User(
    name: viewModel.name,
    address: viewModel.address,
    city: viewModel.city
)

The user constant is initialized with the values from the RegistrationFormViewModel instance. You can then use this User instance to save the data to a database or other storage location, or to pass the data to another part of your app for further processing.

And how do I populate the fields on the view model from the struct?

class RegistrationFormViewModel: ObservableObject {
    @Published var name: String = ""
    @Published var address: String = ""
    @Published var city: String = ""

    var isValid: Bool {
        return !name.isEmpty && !address.isEmpty && !city.isEmpty
    }

    func populate(with user: User) {
        name = user.name
        address = user.address
        city = user.city
    }
}

Use this method to populate the form fields:

let user = User(
    name: "Oliver Doe",
    address: "100 Main St",
    city: "Anytown"
)

viewModel.populate(with: user)

The user constant is initialized with some sample data, and then the populate(with:) method is called on the viewModel instance, passing in the user instance as a parameter. This will set the values of the view model's properties to match the values of the User instance, which will in turn populate the form fields with the data from the User instance.

Tags:
Hubs:
Total votes 5: ↑4 and ↓1+3
Comments1

Articles