I have one view (with a Form), a viewModel, and a second view that I hope to display inputs in the Form of the first view. I thought property wrapping birthdate with @Published in the viewModel would pull the Form input, but so far I can't get the second view to read the birthdate user selects in the Form of the first view.
Here is my code for my first view:
struct ProfileFormView: View {
@EnvironmentObject var appViewModel: AppViewModel
@State var birthdate = Date()
var body: some View {
NavigationView {
Form {
Section(header: Text("Personal Information")) {
DatePicker("Birthdate", selection: $birthdate, displayedComponents: .date)
}
}
}
Here is my viewModel code:
class AppViewModel: ObservableObject {
@Published var birthdate = Date()
func calcAge(birthdate: String) -> Int {
let dateFormater = DateFormatter()
dateFormater.dateFormat = "MM/dd/yyyy"
let birthdayDate = dateFormater.date(from: birthdate)
let calendar: NSCalendar! = NSCalendar(calendarIdentifier: .gregorian)
let now = Date()
let calcAge = calendar.components(.year, from: birthdayDate!, to: now, options: [])
let age = calcAge.year
return age!
and here is my second view code:
struct UserDataView: View {
@EnvironmentObject var viewModel: AppViewModel
@StateObject var vm = AppViewModel()
var body: some View {
VStack {
Text("\(vm.birthdate)")
Text("You are signed in")
Button(action: {
viewModel.signOut()
}, label: {
Text("Sign Out")
.frame(width: 200, height: 50)
.foregroundColor(Color.blue)
})
}
}
And it may not matter, but here is my contentView where I can tab between the two views:
struct ContentView: View {
@EnvironmentObject var viewModel: AppViewModel
var body: some View {
NavigationView {
ZStack {
if viewModel.signedIn {
ZStack {
Color.blue.ignoresSafeArea()
.navigationBarHidden(true)
TabView {
ProfileFormView()
.tabItem {
Image(systemName: "square.and.pencil")
Text("Profile")
}
UserDataView()
.tabItem {
Image(systemName: "house")
Text("Home")
}
}
}
}
else
{
SignInView()
}
}
}
.onAppear {
viewModel.signedIn = viewModel.isSignedIn
}
}
One last note, I've got a second project that requires this functionality (view to viewmodel to view) so skipping the viewmodel and going direct from view to view will not help.
Thank you so much!!
Using a class AppViewModel: ObservableObject
like you do is the appropriate way to "pass" the data around your app views. However, there are a few glitches in your code.
In your first view (ProfileFormView), remove @State var birthdate = Date()
and use
DatePicker("Birthdate", selection: $appViewModel.birthdate, ...
.
Also remove @StateObject var vm = AppViewModel()
in your second view (UserDataView),
you already have a @EnvironmentObject var viewModel: AppViewModel
, no need for 2 of them.
Put @StateObject var vm = AppViewModel()
up in your hierarchy of views,
and pass it down (as you do) using the @EnvironmentObject
with
.environmentObject(vm)
Read this info to understand how to manage your data: https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app