I'm building a SwiftUI app where I have a list of notes. I want to add a new note to the list when a button is clicked and immediately navigate to the detail view of that new note, similar to what happens when clicking a NavigationLink
.
Here’s my current code:
import SwiftUI
import SwiftData
struct NoteList: View {
let folder: Folder
@Query(sort: \Note.lastModified) private var notes: [Note]
@Environment(\.modelContext) private var context
var body: some View {
List {
ForEach(folder.notes) { note in
NavigationLink() {
NoteView(note: note)
} label: {
Text(note.title)
}
}
}
.navigationTitle(folder.name)
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button("Add Note", systemImage: "square.and.pencil") {
let newNote = Note(title: " ", folder: folder)
folder.notes.append(newNote)
context.insert(newNote)
}
}
}
}
}
The folder.notes
array contains Note
objects. When the "Add Note" button is clicked, I can successfully add a new note to the list, but I don’t know how to programmatically navigate to the new note’s detail view (NoteView
).
How can I achieve this in SwiftUI? Any guidance would be greatly appreciated!
I also tried wrapping the button with a NavigationLink
like this:
NavigationLink(destination: NoteView(note: newNote)) {
Button("Add Note", systemImage: "square.and.pencil") {
let newNote = Note(title: " ", folder: folder)
folder.notes.append(newNote)
context.insert(newNote)
self.newNote = newNote
}
}
However, this approach didn't work as expected because newNote
wouldn't be set or updated before the navigation occurred. I'm not entirely sure how to correctly handle this.
Try this approach using NavigationStack(path: $path)
as shown in the example code. This will navigate to the new list item immediately after adding it.
struct ContentView: View {
@State private var folder = Folder(notes: []) // <--- for my testing
@State private var path = NavigationPath() // <--- here
var body: some View {
NavigationStack(path: $path) {
NoteList(path: $path, folder: folder)
.navigationDestination(for: Note.self) { note in
NoteView(note: note)
}
}
}
}
struct NoteList: View {
@Binding var path: NavigationPath // <--- here
let folder: Folder
@Query(sort: \Note.lastModified) private var notes: [Note]
@Environment(\.modelContext) private var context
var body: some View {
List {
ForEach(folder.notes) { note in
NavigationLink() {
NoteView(note: note)
} label: {
Text(note.title)
}
}
}
.navigationTitle(folder.name)
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button("Add Note", systemImage: "square.and.pencil") {
let rnd = UUID().uuidString.prefix(6) // <--- for testing
let newNote = Note(title: String(rnd), folder: folder)
folder.notes.append(newNote)
context.insert(newNote)
path.append(newNote) // <--- here
}
}
}
}
}
// <--- for testing
struct NoteView: View {
let note: Note
var body: some View {
Text("NoteView")
Text(note.title)
}
}