scientiffic
scientiffic

Reputation: 9415

Push View Programmatically After State Variable Defined

In my UI, I have a button for users to create a new project. When the button is tapped, I want to trigger a new view to load for the newly created project.

I understand that I can use NavigationLink with isActive set to a state variable, but the parameter that needs to be passed to the new view has not yet been defined on load (only after the project is created). How can I prevent errors about the project entity not being defined yet?

For example:

struct FirstView: View {
    @State var newProject: Project = Project()
    @State var pushNewProject:Bool = false

var body: some View {
...
    .toolbar{
            ToolbarItem(placement: .navigationBarTrailing){
                Button(action: {
                    self.newProject = Project.create(context: viewContext)
                    self.pushNewProject = true
                }){
                   Text("Create Project")
                }
            }
        }// toolbar

        NavigationLink(destination:
                        ProjectSideBar(project:  self.newProject),
           isActive: self.$pushNewProject) {
             EmptyView()
        }.hidden()
}

Upvotes: 0

Views: 365

Answers (1)

jnpdx
jnpdx

Reputation: 52387

You could make your newProject an optional, since you don't really want the value until it's created. Then, you can use an if let optional binding to only return the destination to ProjectSideBar available if there's a value.

Here's a simplified version of your code:

struct Project {
    var name: String
}

struct FirstView: View {
    @State var newProject: Project?
    @State var pushNewProject:Bool = false
    
    @ViewBuilder var navDestination : some View {
        if let newProject = newProject {
            ProjectSideBar(project:  newProject)
        } else {
            EmptyView()
        }
    }
    
    var body: some View {
        NavigationView {
            VStack {
                Button(action: {
                    self.newProject = Project(name: "test")
                    self.pushNewProject = true
                }){
                    Text("Create Project")
                }
                
                NavigationLink(destination: navDestination,
                               isActive: self.$pushNewProject) {
                    EmptyView()
                }.hidden()
            }
        }
    }
}

struct ProjectSideBar : View {
    var project : Project
    
    var body: some View {
        Text(project.name)
    }
}

Note that I tried using an if let around the NavigationLink first, without having to do the navDestination computed property, but that results in a situation where there's not an animation to the new view. I believe this used to work, but as of iOS 15, it seems to need the NavigationLink in the hierarchy the whole time to get the animation.

Upvotes: 1

Related Questions