Home > Software engineering >  Selecting an existing item on an array or passing a new one to a .sheet
Selecting an existing item on an array or passing a new one to a .sheet

Time:03-17

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.

  • Related