macosswiftuimacos-big-sur

Deleting an item from a list based on the element UUID


I feel a bit embarrassed for asking this, but after more than a day trying I'm stuck. I've had a few changes on the code based on replies to other issues. The latest code essentially selects the items on a list based on the UUID.

This has caused my delete function to stop working since I was working with passing an Int as the selected element to be deleted. I was originally implementing things like this.

Code follows, I'm still trying to figure out my way around SwiftUI, but question is, how can I now delete items on a list (and on the array behind it) based on a UUID as opposed to the usual selected item.

In case it makes a difference, this is for macOS Big Sur.

Code:

struct NoteItem: Codable, Hashable, Identifiable {
    let id: Int
    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 AllNotes: View {
    
    @EnvironmentObject private var data: DataModel
    
    @State var noteText: String = ""
    @State var selectedNoteId: UUID?
    
    var body: some View {
        NavigationView {
            List(data.notes) { note in
                NavigationLink(
                    destination: NoteView(note: note),
                    tag: note.id,
                    selection: $selectedNoteId
                ) {
                    VStack(alignment: .leading) {
                        Text(note.text.components(separatedBy: NSCharacterSet.newlines).first!)
                        Text(note.dateText).font(.body).fontWeight(.light)
                    }
                    .padding(.vertical, 8)
                }
            }
            .listStyle(InsetListStyle())
        }
        .navigationTitle("A title")
        .toolbar {
            ToolbarItem(placement: .navigation) {
                Button(action: {
                    data.notes.append(NoteItem(id: UUID(), text: "New Note", date: Date(), tags: []))
                }) {
                    Image(systemName: "square.and.pencil")
                }
            }

            ToolbarItem(placement: .automatic) {
                Button(action: {
                    // Delete here????
                }) {
                    Image(systemName: "trash")
                }               
            }
        }
        .onAppear {
            DispatchQueue.main.async {
                selectedNoteId = data.notes.first?.id
            }
        }
        .onChange(of: data.notes) { notes in
            if selectedNoteId == nil || !notes.contains(where: { $0.id == selectedNoteId }) {
                selectedNoteId = data.notes.first?.id

            }
        }
    }
}

The original removeNote I had is the following:

func removeNote() {
     if let selection = self.selectedItem,
         let selectionIndex = data.notes.firstIndex(of: selection) {
                print("delete item: \(selectionIndex)")
                data.notes.remove(at: selectionIndex)
         }
}

Solution

  • could you try this:

    struct NoteItem: Codable, Hashable, Identifiable {
        let id: UUID  // <--- here
        var text: String
        var date = Date()
        var dateText: String = ""
        var tags: [String] = []
    }
    
    func removeNote() {
        if let selection = selectedNoteId,
           let selectionIndex = data.notes.firstIndex(where: { $0.id == selection }) { 
            print("delete item: \(selectionIndex)")
            data.notes.remove(at: selectionIndex)
        }
    }