2

This is more of a general understanding question regarding SwiftUI.

What I would like to be able to do is to execute a function associated with another view. There are a number of cases/reasons for doing this. My most recent endeavor is to have a view that collects a number of fields, like an address, then to use that view within other views.

My question is, how do I get the data from the address view? In the example shown, how might I call the getXML() function? Is there a better way to accomplish this?

import SwiftUI

struct AddressView: View
{
    @State var street1 = ""
    @State var street2 = ""
    @State var city = ""
    @State var state = ""
    @State var zip = ""

    var body: some View
    {
        VStack
        {
            TextField("Street1", text: $street1)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Street2", text: $street2)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("City", text: $city)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("State", text: $state)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Zip", text: $zip)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            
        }.padding()
    }
    
    func getXML() -> String
    {
        var xml = XMLStuff("Address")
        xml.push(tag: "street1", value: street1)
        xml.push(tag: "street2", value: street2)
        xml.push(tag: "city", value: city)
        xml.push(tag: "state", value: state)
        xml.push(tag: "zip", value: zip)
        return xml.string()
    }
}

The following is some code that would be used to include several such views but I can't figure out how to extract the data in order to save/use it.

import SwiftUI

struct ContactView: View
{
    @State var name: String = ""
    
    var body: some View
    {
        VStack
        {
            TextField("Name", text: $name)
            AddressView()
            PhoneView()
        }
    }
}

I know I could create a bunch of state variables in the caller and then pass them to the sub-view, but I'm trying to avoid that if possible.

1
  • 1
    Instead of bunch of states you need one view model that is owned by ContactView and passed into AddressView, which modify it, and parent view just use it, and getXML can be placed in that view model class. Commented Dec 8, 2020 at 19:38

1 Answer 1

2

You can create an ObservableObject class to store your properties:

class ContactViewModel: ObservableObject {
    @Published var street1 = ""
    @Published var street2 = ""
    @Published var city = ""
    @Published var state = ""
    @Published var zip = ""

    func getXML() -> String {
        var xml = XMLStuff("Address")
        xml.push(tag: "street1", value: street1)
        xml.push(tag: "street2", value: street2)
        xml.push(tag: "city", value: city)
        xml.push(tag: "state", value: state)
        xml.push(tag: "zip", value: zip)
        return xml.string()
    }
}

Then, use this class in the ContentView:

struct ContactView: View {
    @StateObject private var viewModel = ContactViewModel()
    @State private var name: String = ""

    var body: some View {
        VStack {
            TextField("Name", text: $name)
            AddressView(viewModel: viewModel)
            ...
        }
    }
}

and pass it to the AddressView:

struct AddressView: View {
    @ObservedObject var viewModel: ContactViewModel

    var body: some View {
        VStack {
            TextField("Street1", text: $viewModel.street1)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Street2", text: $viewModel.street2)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("City", text: $viewModel.city)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("State", text: $viewModel.state)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Zip", text: $viewModel.zip)
                .textFieldStyle(RoundedBorderTextFieldStyle())

        }.padding()
    }
}

You can also call the getXML() function from either ContentView or AddressView:

viewModel.getXML()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.