listswiftuinavigationlink

How to edit an item in a list using NavigationLink?


I am looking for some guidance with SwiftUI please.

I have a view showing a simple list with each row displaying a "name" string. You can add items to the array/list by clicking on the trailing navigation bar button. This works fine. I would now like to use NavigationLink to present a new "DetailView" in which I can edit the row's "name" string. I'm struggling with how to use a binding in the detailview to update the name.

I've found plenty of tutorials online on how to present data in the new view, but nothing on how to edit the data. Thanks in advance.

ContentView:

struct ListItem: Identifiable {
    let id = UUID()
    let name: String
}

class MyListClass: ObservableObject {
    @Published var items = [ListItem]()
}

struct ContentView: View {

    @ObservedObject var myList = MyListClass()

    var body: some View {
        NavigationView {
            List {
                ForEach(myList.items) { item in
                    NavigationLink(destination: DetailView(item: item)) {
                        Text(item.name)
                    }
                }
            }
            .navigationBarItems(trailing:
                Button(action: {
                    let item = ListItem(name: "Test")
                    self.myList.items.append(item)
                }) {
                    Image(systemName: "plus")
                }
            )
        }
    }
}

DetailView

struct DetailView: View {

    var item: ListItem

    var body: some View {
        TextField("", text: item.name)
    }
}

Solution

  • The main idea that you pass in DetailsView not item, which is copied, because it is a value, but binding to the corresponding item in your view model.

    Here is a demo with your code snapshot modified to fulfil the requested behavior:

    struct ListItem: Identifiable, Equatable {
        var id = UUID()
        var name: String
    }
    
    class MyListClass: ObservableObject {
        @Published var items = [ListItem]()
    }
    
    struct ContentView: View {
    
        @ObservedObject var myList = MyListClass()
    
        var body: some View {
            NavigationView {
                List {
                    ForEach(myList.items) { item in
                        // Pass binding to item into DetailsView
                        NavigationLink(destination: DetailView(item: self.$myList.items[self.myList.items.firstIndex(of: item)!])) {
                            Text(item.name)
                        }
                    }
                }
                .navigationBarItems(trailing:
                    Button(action: {
                        let item = ListItem(name: "Test")
                        self.myList.items.append(item)
                    }) {
                        Image(systemName: "plus")
                    }
                )
            }
        }
    }
    
    struct DetailView: View {
    
        @Binding var item: ListItem
        
        var body: some View {
            TextField("", text: self.$item.name)
        }
    }