I have an array that contains the data that is displayed on a list. When the user hits "new", a sheet pops up to allow the user to enter a new item to the list.
I just added a swipe option to edit this item and I wanted to reuse the same sheet to edit the item's text. But I'm having problems understanding how to check whether a specific item was selected (by UUID?) to pass to the sheet, or it's a new item.
Code:
let dateFormatter = DateFormatter()
struct NoteItem: Codable, Hashable, Identifiable {
let id: UUID
var text: String
var date = Date()
var dateText: String {
dateFormatter.dateFormat = "EEEE, MMM d yyyy, h:mm a"
return dateFormatter.string(from: date)
}
var tags: [String] = []
}
struct ContentView: View {
@EnvironmentObject private var data: DataModel
@State private var selectedItemId: UUID?
@State var searchText: String = ""
@State private var sheetIsShowing = false
NavigationView {
List(filteredNotes) { note in
VStack(alignment: .leading) {
//....
// not relevant code
}
.swipeActions(allowsFullSwipe: false) {
Button(action: {
selectedItemId = note.id
self.sheetIsShowing = true
} ) {
Label("Edit", systemImage: "pencil")
}
}
}
.toolbar {
// new item
Button(action: {
self.sheetIsShowing = true
}) {
Image(systemName: "square.and.pencil")
}
}
.sheet(isPresented: $sheetIsShowing) {
if self.selectedItemId == NULL { // <-- this is giving me an error
let Note = NoteItem(id: UUID(), text: "New Note", date: Date(), tags: [])
SheetView(isVisible: self.$sheetIsShowing, note: Note)
} else {
let index = data.notes.firstIndex(of: selectedItemId)
SheetView(isVisible: self.$sheetIsShowing, note: data.notes[index])
}
}
}
}
My rationale was to check whether self.selectedItemId == NULL
was null or not, if not then pass that element to the sheet to be edited, if yes, the as it as a new element.
What am I doing wrong? And if there is a standard way to pass information to the sheet based on whether there is an item select or not, could you show me?
Thanks!
CodePudding user response:
From this post, you can do like this in your case:
struct SheetForNewAndEdit: View {
@EnvironmentObject private var data: DataModel
@State var searchText: String = ""
// The selected row
@State var selectedNote: NoteItem? = nil
@State private var sheetNewNote = false
// for test :
@State private var filteredNotes: [NoteItem] = [
NoteItem(id: UUID(), text: "111"),
NoteItem(id: UUID(), text: "222")];
var body: some View {
NavigationView {
List(filteredNotes) { note in
VStack(alignment: .leading) {
//....
// not relevant code
Text(note.text)
}
.swipeActions(allowsFullSwipe: false) {
Button(action: {
// the action select the note to display
selectedNote = note
} ) {
Label("Edit", systemImage: "pencil")
}
}
}
// sheet is displayed depending on selected note
.sheet(item: $selectedNote, content: {
note in
SheetView(note: note)
})
// moved tool bar one level (inside navigation view)
.toolbar {
// Toolbar item to have toolbar
ToolbarItemGroup(placement: .navigationBarTrailing) {
ZStack {
Button(action: {
// change bool value
self.sheetNewNote.toggle()
}) {
Image(systemName: "square.and.pencil")
}
}
}
}
.sheet(isPresented: $sheetNewNote) {
let Note = NoteItem(id: UUID(), text: "New Note", date: Date(), tags: [])
SheetView(note: Note)
}
}
}
}
Note : SheetView does not need any more a boolean, but you can add one if you orefer
CodePudding user response:
Swift uses nil
, not null
, so the compiler is complaining when you are comparing selected items to null
. However, you will have another issue. Your selectedItemId
is optional, so you can't just use it in your else clause to make your note
. You are better off using an if let
to unwrap it. Change it to:
.sheet(isPresented: $sheetIsShowing) {
if let selectedItemId = selectedItemId,
let index = data.notes.firstIndex(where: { $0.id == selectedItemId }) {
SheetView(isVisible: self.$sheetIsShowing, note: data.notes[index])
} else {
let note = NoteItem(id: UUID(), text: "New Note", date: Date(), tags: [])
SheetView(isVisible: self.$sheetIsShowing, note: note)
}
}
edit:
I realized that you were attempting to use two optionals without unwrapping them, so I changed this to an if let to make sure both are safely unwrapped.