Learn Courses My Dashboard

How to disabled a button when a core data variable changes in SwiftUI?

I am trying to disable a button based on a computed property from the View Model, but is only disabled after the view is reloaded.

This is the View Model :

  class VerifyFieldViewModel : ObservableObject {
    @ObservedObject var coreDataViewModel = CoreDataViewModel()
    func isValidFirstName() -> Bool {
        guard coreDataViewModel.savedDetails.first?.firstName?.count ?? 0 > 0 else {
            return false
        }
        return true
    }
    func isValidLastName() -> Bool {
        guard coreDataViewModel.savedDetails.first?.lastName?.count ?? 0 > 0 else {
            return false
        }
        return true
    }

    var isFirstNameValid : String {
        if isValidFirstName() {
       return ""
        } else {
        return "Name is empty"
        }
    }
    
    var isLastNameValid : String {
        if isValidLastName() {
       return ""
        } else {
        return "Surname is empty"
        }
    }
    
   var isSignUpComplete: Bool {
        if !isValidFirstName() || !isValidLastName() {
            return false
        }
        return true
    }
    }

This is how I am disabling the button .

struct CartsView: View {
    @State var onboardingState: Int = 0
    @StateObject var coreDataViewModel = CoreDataViewModel()
    @ObservedObject var verifyFieldViewModel = VerifyFieldViewModel()
    var body: some View {
        ZStack {
            switch onboardingState {

            case 0 :
                VStack {
                detailOrder
                    .transition(transition)
                Spacer()
                bottomButton
                    .padding(30)
                }
            case 1 :
                VStack {
                detailOrder2. -> This is LivrareView
                    .transition(transition)
                    Spacer()
                    bottomButton
                        .padding(30)
                        .opacity(verifyFieldViewModel.isSignUpComplete ? 1 : 0.6)
                        .disabled(!verifyFieldViewModel.isSignUpComplete)
                }
            default:
                EmptyView()
            }
        }
}
}

This is the Core Data View Model :

class CoreDataViewModel  : ObservableObject {
    let manager = CoreDataManager.instance
    @Published var savedDetails : [Details] = []
    init() {
        fetchSavedDetails()
    }
    func fetchSavedDetails() {
        let request = NSFetchRequest<Details>(entityName: "Details")
        do {
            savedDetails = try manager.context.fetch(request)
        } catch let error {
            print("Error fetching \(error)")
        }
    }
    
    
    func saveContext() {
        DispatchQueue.main.async {
            self.manager.save()
            self.fetchSavedDetails()
        }
        }

}
struct LivrareView: View {
    @StateObject var coreDataViewModel = CoreDataViewModel()
    @EnvironmentObject var syncViewModel : SyncViewModel
    @ObservedObject var verifyFieldsViewModel = VerifyFieldsViewModel()
    var body: some View {
        let firstName = Binding(
            get: {coreDataViewModel.savedDetails.first?.firstName ?? ""},
            set: {coreDataViewModel.savedDetails.first?.firstName = $0})
        
        let lastName = Binding(
            get: {coreDataViewModel.savedDetails.first?.lastName ?? ""},
            set: {coreDataViewModel.savedDetails.first?.lastName = $0})
        
        ScrollView {
            VStack(alignment: .leading) {
                Text("First Name")
                    .padding(.top)
                    .foregroundColor(.orange)
                EntryField(placeHolder: "Name", prompt: $verifyFieldsViewModel.isFirstNameValid, field: firstName)
                    .onSubmit {
                        coreDataViewModel.saveContext()
                    }
                Text("Last Name")
                    .padding(.top)
                    .foregroundColor(.orange)
                EntryField(placeHolder: "Last Name", prompt: $verifyFieldsViewModel.isLastNameValid, field: lastName)
                
                    .onSubmit {
                        coreDataViewModel.saveContext()
                    }
            }
        }
    }

NOTE : It works, but only when the view is reloaded.

How can i make this work?. I’ve tried

Using the modifier .disabled(Bool) is the way to do that such that when the Bool is true the button is disabled.

You might need to post the code that defines bottomButton so that we know what’s going on with that code.