Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Showing alert with an error does not work when using a ViewModel

I am trying to find a way to use the new alert(isPresented:error:actions:message:). My motivation is to find a good way to throw a custom error and have a user facing alert using that error.

My issue is that this works when using local bindings but not when using a ViewModel. I don’t see where I am doing anything wrong, so I am wondering whether this is an error I should file a radar for?

This is my custom error, that implements the LocalizedError protocol:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

struct CustomError: LocalizedError {
    var errorDescription: String?
    var failureReason: String?
    var helpAnchor: String?
    var recoverySuggestion: String?
}

This view is working just fine:

struct AlertViewWithoutViewModel: View {
    @State private var presentAlert = false
    @State private var error: CustomError?
    
    var body: some View {
        Button("Show alert without ViewModel") {
            error = CustomError(errorDescription: "Description of the error", failureReason: "It went wrong.")
            presentAlert = true
        }
        .padding()
        .alert(isPresented: $presentAlert, error: error) { error in
            Button("OK") {}
        } message: { error in
            if let failureReason = error.failureReason {
                Text(failureReason)
            }
        }

    }
}

What is not working is using this ViewModel––and I don’t understand why:

class ViewModel: ObservableObject {
    @Published var presentAlert = false
    @Published var error: CustomError?
}

struct AlertViewWithViewModel: View {
    @State private var vm = ViewModel()
    
    var body: some View {
        Button("Show alert with ViewModel") {
            vm.error = CustomError(errorDescription: "Fancy VM error title", failureReason: "Some fancy reason.")
            vm.presentAlert = true
        }
        .alert(isPresented: $vm.presentAlert, error: vm.error) { error in
            Button("OK") {}
        } message: { error in
            if let failureReason = error.failureReason {
                Text(failureReason)
            }
        }
    }
}

>Solution :

You need StateObject wrapper (which is observer for ObservableObject) instead of State (which for value types),

struct AlertViewWithViewModel: View {
    @StateObject private var vm = ViewModel()    // << here !!
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading