0

SwiftUI [This is the code for the list and my button]

ForEach(items, id: \.self) { current in 
                VStack(alignment: .leading) {
                    Text("\(current.task)")
                        .padding(2)
                    Text("\(dateFormatter.string(from: current.date))")
                    Button(action: {}, 
                           label: {
                                    Image(systemName: 
                                      "checkmark.rectangle.fill")
                            .resizable()
                            .frame(width: 50, height: 35)
                           }) 
}

Items is my array containing a string and a date. Here is the code for it:

@State var items:[Tasks] = [Tasks(task: "Test", date: Date())]

And here is Tasks:

struct Tasks: Hashable {
  let task: String
  let date: Date 
}

This is my list view

I want to have a user be able to click a button under each list item and it will remove that list item. I am currently using the onDelete method but I would prefer to have a confirm button in each list item that would allow the user to remove that list item.

    @State var counter = -1 

I tried using a counter that would increase by 1 each time the ForEach loop ran and create a new variable inside of that ForEach loop equal to it. However I could not access the variable inside of the button to use as an index.

1
  • 1
    Please check this link: posting a picture fo your code is not helpful. You should post text, that we can select and test. And it must be a minimal reproducible example - how do we know what is items in your code? Commented Feb 18, 2023 at 22:35

1 Answer 1

1

Using your current code structure, assuming each task: String is unique, you could just add this to your Button action:

 Button(action: {
     if let index = items.firstIndex(where: {$0.task == current.task}) {
         items.remove(at: index)
     }
 },
        label: {
     Image(systemName: "checkmark.rectangle.fill")
         .resizable()
         .frame(width: 50, height: 35)
 })

However, it would be more robust to add an id property to your Task, and at the same time rename it, because Swift already defines Task as part of its async/await framework.

Here is the complete code I use to test my answer:

struct MyTask: Identifiable, Hashable { // <--- here
  let id = UUID() // <--- here
  let task: String
  let date: Date
}

struct ContentView: View {
    @State var items:[MyTask] = [
        MyTask(task: "Test1", date: Date()),
        MyTask(task: "Test2", date: Date().addingTimeInterval(60*60*24*44)),
        MyTask(task: "Test3", date: Date().addingTimeInterval(60*60*24*88))
    ]
    
    var body: some View {
        ForEach(items) { current in     // <--- here
            VStack(alignment: .leading) {
                Text(current.task).padding(2)  // <--- here
                Text(dateFormatter.string(from: current.date))  // <--- here
                Button(action: {
                    // --- here
                    if let index = items.firstIndex(where: {$0.id == current.id}) {
                        items.remove(at: index)
                    }
                },
                       label: {
                    Image(systemName: "checkmark.rectangle.fill").resizable()
                        .frame(width: 50, height: 35)
                })
            }
        }
    }
    
    var dateFormatter: DateFormatter = {
        let frmt = DateFormatter()
        frmt.dateFormat = "yyyy-MMM-dd"
        return frmt
    }()
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.