SwifUI activates all available indices in ForEach

Viewed 272

I have a problem programmatically opening and closing a View in SwiftUI:

With the code below SwiftUI opens each index of contactsArray one after another, when clicking on one of them (it loops through all of them). Of course it should just open the one I clicked on.

I thought the problem might rely on the id but my Model is Identifiable.

ContactsView:

               // ...
                List {
                    ForEach(contactsViewModel.contactsArray, id: \.self) {
                        contact in
                        NavigationLink(destination: ContactsDetailsView(contact: contact), isActive: self.$userViewModel.showContacts) {
                            Text(contact.surname).bold() + Text(", ") + Text(contact.forename)
                        }
                    }
                }

ContactsViewModel:

final class ContactsViewModel: ObservableObject {    
   @Published var contactsArray: [ContactModel] = []
   // ...
}

ContactModel:

struct ContactModel: Decodable, Identifiable, Equatable, Hashable, Comparable {
    var id: String
    var surname: String
    var forename: String
    var telephone: String
    var email: String
    var picture: String
    var gender: String
    var department: String
    
    static func < (lhs: ContactModel, rhs: ContactModel) -> Bool {
        if lhs.surname != rhs.surname {
            return lhs.surname < rhs.surname
        } else {
            return lhs.forename < rhs.forename
        }
    }
    
    static func == (lhs: ContactModel, rhs: ContactModel) -> Bool {
        return lhs.surname == rhs.surname  && lhs.forename == rhs.forename
    }
}
1 Answers

You join all NavigationLink/s to one state (one-to-many), so, no surprise, when you toggle this state all links are activated.

Instead you need something like the following

@State private var selectedContact: String? = nil // or put it elsewhere

...

NavigationLink(destination: ContactsDetailsView(contact: contact), 
               tag: contact.id, selection: $selectedContact) {
    Text(contact.surname).bold() + Text(", ") + Text(contact.forename)
}

, where selectedContact is id of contact link to be activated. Then all you need is to decide which contact id to assign to selectedContact.

Related