Search code examples
swiftswiftui

Trying to access Swift UI column selection property other than the ID


I am displaying a table using data from a custom data type (in this case, General) which contains a number of properties (name, policyId, category etc)

When I select a row I am using the following @state vars to select and sort the data

 @State private var selectedPolicyIDs = Set<General.ID>()
 @State private var sortOrder = [KeyPathComparator(\General.policyId)]

My selection gives me the UUID of the data object, but I want to access a different property (in this case the policyId property rather than UUID) to pass it to a function

This is the code:

struct General: Codable, Hashable, Identifiable {
var id = UUID()
let policyId: Int?
let name: String?

}

Table(networkController.allPoliciesDetailedGeneral, selection: $selectedPolicyIDs, sortOrder: $sortOrder) {
    
    TableColumn("Name", value: \.name!)
    TableColumn("Category", value: \.category!.name)
    TableColumn("ID") {
        policy in
        Text(String(policy.policyId ?? 0))
    }
}
.onChange(of: sortOrder) { newOrder in
    networkController.allPoliciesDetailedGeneral.sort(using: newOrder)
}

Is there a way that I can map the UUID to the policyId value so that I can access that when I select a row - or that I can have access to the entire object, to be able to pass it to the function?

I also need to be able to select multiple items, so I am wanting to pass a set of policyIds (or entire General objects) instead of the current set of UUIDs that I can access.

I am thinking that it would be possible to do a computed property to dynamically match the UUID from the selection with the relevant item from the array, or another calculation that triggers each time the item is selected, but my brain is drawing a blank coming up with it.


Solution

  • You have some array of General objects that is your data source for the table, lets call it

    var dataSource: [General]
    

    then you can convert the selected ID's from selectedPolicyIDs to an array of objects doing

    let selectedObjects = dataSource.filter { selectedPolicyIDs.contains($0.id) }
    

    or if you want the policyId instead you can add map

    let selectedObjects = dataSource.filter { selectedPolicyIDs.contains($0.id) }
        .map(\.policyId)
    

    If you only need/want to select single objects you could change the solution to

    var selection: General.ID?
    
    if let selection, let object = dataSource.first(where: { $0.id == selection })
        //... call function
    }
    

    It’s not clear when you want to call this function, if it’s directly or when some button is clicked for instance but if’s directly then add an onChange modifier for the selectedPolicyIDs property