There are many ways to achieve what you want. This is just one approach, by passing the profileViewModel to EditProfile:
class ProfileViewModel: ObservableObject { @Published var user = Profile(id: "", image: "", birthDay: "", role: [], gender: "", name: "") private var ref: DatabaseReference = Database.database().reference() func fetchData(userId: String? = nil) { // 8hOqqnFlfGZTj1u5tCkTdxAED2I3 ref.child("users").child(userId ?? "default").observe(.value) { [weak self] (snapshot) in guard let self = self, let value = snapshot.value else { return } do { print("user: \(value)") self.user = try FirebaseDecoder().decode(Profile.self, from: value) } catch let error { print(error) } } } func saveUser() { // save the user using your ref DatabaseReference // using setValue, or updateChildValues // see https://firebase.google.com/docs/database/ios/read-and-write } } struct EditProfile: View { @ObservedObject var profileViewModel: ProfileViewModel // <--- here var body: some View { VStack { Text(profileViewModel.user.name) // <--- you probably meant TextField .font(.custom("Poppins-Regular", size: 15)) .foregroundColor(Color.black) Text("\(profileViewModel.user.birthDay)!") .font(.custom("Poppins-Regular", size: 22)) .fontWeight(.bold) .foregroundColor(Color.black) Text("\(profileViewModel.user.gender)") .font(.custom("Poppins-Regular", size: 22)) .fontWeight(.bold) .foregroundColor(Color.black) Text(profileViewModel.user.role.first ?? "") .font(.custom("Poppins-Regular", size: 22)) .fontWeight(.bold) .foregroundColor(Color.black) Button(action: { // save the profileViewModel.user to database profileViewModel.saveUser() // <--- here }) { Text("Save") } } .padding() } } struct CategoriesView: View { @ObservedObject var viewModel = SectionViewModel() @EnvironmentObject var loginViewModel : LoginViewModel @StateObject var profileViewModel = ProfileViewModel() var body: some View { ZStack { VStack (alignment: .leading, spacing:0) { EditProfile(profileViewModel: profileViewModel) // <--- here .padding() .padding(.bottom,-10) } } .onAppear() { self.viewModel.fetchData() profileViewModel.fetchData(userId: loginViewModel.session?.uid) } } }
EDIT1: regarding the updated code.
In your new code, in ProfileHost you are not passing ProfileViewModel. Use:
NavigationLink(destination: ProfileEditor(profileViewModel: viewModel)) { ProfileRow(profileSetting: profile) }
And in ProfileEditor replace profile with profileViewModel.user
You will probably need to adjust profileItem and put it in a .onAppear {...} . Something like this:
struct ProfileEditor: View { @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode> @ObservedObject var profileViewModel: ProfileViewModel @EnvironmentObject var loginViewModel: LoginViewModel let profileLabel: [String] = ["Name", "Account", "Gender", "Role", "Email"] @State var profileItem: [String] = [] @State var profileEditorRow: [ProfileEditorItem] = [] var body: some View { VStack { ForEach(profileEditorRow) { editor in if editor.id == 5 { ProfileEditorRow(editor: editor, showLastLine: true) } else { ProfileEditorRow(editor: editor, showLastLine: false) } } Button("Save") { profileViewModel.updateData(userId: loginViewModel.session?.uid) } } .onAppear { profileItem = [profileViewModel.user.name, profileViewModel.user.birthDay, profileViewModel.user.gender, profileViewModel.user.role.first ?? "", profileViewModel.user.birthDay] for n in 1...5 { profileEditorRow.append(ProfileEditorItem(id: n, label: profileLabel[n-1], item: profileItem[n-1])) } } } }
EDIT2: update func
func updateData() { ref.("users").child(user.id).updateChildValues([ "name": user.name, "birthDay": user.birthDay, "gender": user.gender, "role": user.role.first ?? ""]) }
and use this in ProfileEditor :
Button("Save") { profileViewModel.updateData() }