I am attempting to clear variable values when a button is pressed in another view. Code below:
Root view
struct RecipeEditorHomeMenu: View {
@Environment(\.dismiss) var dismiss
@State var recipeAddedSuccess = false
@State private var showSaveButton = false
@State var showSuccessMessage = false
@State private var sheetMode: SheetMode = .none
@ObservedObject var recipeClass = Recipe()
var onDismiss: (() -> Void)?
var body: some View {
GeometryReader{ geo in
VStack{
if showSuccessMessage {
RecipeSuccessPopUp(shown: $showSuccessMessage, onDismiss: onDismiss)
}
RecipeEditorView(showSuccessMessage: $showSuccessMessage)
.blur(radius: showSuccessMessage ? 15 : 0)
.padding(.top, 80)
// Spacer()
//display save button
FlexibleSheet(sheetMode: $sheetMode) {
SaveRecipeButton(showSuccessMessage: $showSuccessMessage)
//sets coordinates of view on dash
.offset(y:-200)
}
}
.onAppear{
recipeAddedSuccess = false
}
//center view
.alignmentGuide(VerticalAlignment.center, computeValue: { $0[.bottom] })
.position(x: geo.size.width / 2, y: geo.size.height / 2)
.environmentObject(recipeClass)
}
}
}
EditorView (where I would like to clear variables and refresh the view so now it appears new and no variables have values anymore:
struct RecipeEditorView: View {
@EnvironmentObject var recipeClass: Recipe
@State var recipeTitle = ""
@State private var recipeTime = "Cook Time"
@State private var pickerTime: String = ""
//calls macro pickers@State var proteinPicker: Int = 0
@Binding var showSuccessMessage: Bool
var cookingTime = ["5 Mins", "10 Mins","15 Mins","20 Mins","25 Mins","30 Mins ","45 Mins ","1 Hour","2 Hours", "A Long Time", "A Very Long Time"]
var resetPickerTime: (() -> Void)?
var body: some View {
VStack{
TextField("Recipe Title", text: $recipeTitle)
.onChange(of: recipeTitle, perform: { _ in
recipeClass.recipeTitle = recipeTitle
})
.foregroundColor(Color.black)
.font(.title3)
.multilineTextAlignment(.center)
//macro selectors
HStack{
Picker(selection: $carbPicker, label: Text("")) {
ForEach(pickerGramCounter(), id: \.self) {
Text(String($0) "g Carbs")
}
.onChange(of: carbPicker, perform: { _ in
recipeClass.recipeCarbMacro = carbPicker
})
}
.accentColor(.gray)
}
.accentColor(.gray)
}
HStack(spacing: 0){
ZStack{
Image(systemName:("clock"))
.padding(.leading, 150)
.foregroundColor(Color("completeGreen"))
Picker(selection: $pickerTime, label: Text("Gender")) {
ForEach(cookingTime, id: \.self) {
Text($0)
}
}
.onChange(of: pickerTime, perform: { _ in
recipeClass.recipePrepTime = pickerTime
})
.accentColor(.gray)
}
.multilineTextAlignment(.center)
}
}
}
}
Button where I save the recipes (and would like to clear the variables here:
struct SaveRecipeButton: View {
@Binding var showSuccessMessage: Bool
//stores recipe
@EnvironmentObject var recipeClass: Recipe
@State var isNewRecipeValid = false
static var newRecipeCreated = false
var body: some View {
Button(action: {
//action
}){
HStack{
Image(systemName: "pencil").resizable()
.frame(width:40, height:40)
.foregroundColor(.white)
Button(action: {
if (recipeClass.recipeTitle != "" &&
recipeClass.recipePrepTime != "" &&
){
isNewRecipeValid = true
showSuccessMessage = true
saveRecipe()
}
else{
showSuccessMessage = false
isNewRecipeValid = false
}
}){
Text("Save Recipe")
.font(.title)
.frame(width:200)
.foregroundColor(.white)
}
}
.padding(EdgeInsets(top: 12, leading: 100, bottom: 12, trailing: 100))
.background(
RoundedRectangle(cornerRadius: 10)
.fill(
Color("completeGreen")))
}
.transition(.sideSlide)
.animation(.easeInOut(duration: 0.25))
}
}
My recipe class holds each variable as @Published variables. I tried clearing the variables in this class as well, but the values don't refresh in the view (example: If I have a recipeTitle as "Eggs" and save that recipe down, recipeTitle does not update in the view)
**update recipe class:
class Recipe: ObservableObject, Identifiable {
let id = UUID().uuidString
@Published var recipeTitle: String = ""
@Published var isCompleted = false
@Published var recipeCaloriesMacro: Int = 0
@Published var recipeFatMacro: Int = 0
@Published var recipeProteinMacro: Int = 0
}
CodePudding user response:
I asume you want to reset the values in Recipe
. The reason because this doesn´t reflect into RecipeEditorView
are the @State
values in your RecipeEditorView
.
You are neglecting a basic principle of SwiftUI: "Single source of truth".
RecipeEditorView
has several @State
values that you then bind to your Picker
s and TextField
s. Then you observe their changes and synchronize with your ViewModel Recipe
.
Don´t do that, use the ViewModel itself as the (I know I´m repeating myself here) "Single source of truth".
Another issue. If a view manages the lifecycle of an ObservableObject
like instantiating it and holding on to it, declare it as @StateObject
. @ObservedObject
is only needed it the class is injected and managed up the hierarchy.
In RecipeEditorHomeMenu
:
@StateObject var recipeClass = Recipe()
in RecipeEditorView
remove all that @State
vars that are used to define the recipe e.g.: recipeTitle
, carbPicker
and pickerTime
and bind to the values in the ViewModel.
Possible implementation for recipeTitle
:
// this needs to be changed
TextField("Recipe Title", text: $recipeClass.recipeTitle)
Do this for the others too.
Now in SaveRecipeButton
you can change these vars to whatever value you want. E.g.: resetting the title would look like:
recipeClass.recipeTitle = ""