Home > Net >  How to clear variable when triggered in another view
How to clear variable when triggered in another view

Time:01-27

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 Pickers and TextFields. 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 = ""
  • Related