RobbeR
RobbeR

Reputation: 485

Update an array after Toggle change in SwiftUI

I have a ScooterReservationView class in SwiftUI:

...
@State var extensionIDs: [Int] = []

var body: some View {
    ...
    List(scooterExtensionVM.extensions, id: \.self) { scooterExtension in
            ScooterExtensionRow(_extension: scooterExtension, extensionIDs: self.$extensionIDs)
    }
...

The scooterExtensionVM.extensions array gets its value from an API request, the extensions are totally dynamic based on the backend API. Then I have the ScooterExtensionRow struct:

struct ScooterExtensionRow: View {

@EnvironmentObject var appState: AppState
@Binding var extensionIDs: [Int]

var scooterExtension: ScooterExtension
@State var isOn: Bool = true

init(_extension: ScooterExtension, extensionIDs: Binding<[Int]>) {
    self.scooterExtension = _extension
    self._extensionIDs = extensionIDs
}

var body: some View {
    HStack {
        Toggle(isOn: self.$isOn) {
            Text(scooterExtension.name)
        }
        .padding()
    }
}

}

My goal is to update extensionIDs array when the Toggle inside any of the ScooterExtensionRow view has changed. If any of the Toggle is switch on, I need to add the ScooterExtension's extension ID to that array, if its off, I need to remove the id from the array. This needs me for an API request later. (I need to collect all of the IDs of the enabled/toggled extensions)

The problem is: I cannot see in the docs any kind of callback action for the Toggle, where I can append/remove the value to/from the array, but maybe a callback is not the best way to do it in that Great SwiftUI World.

Can anyone help what is the best way to achieve this?

Upvotes: 3

Views: 888

Answers (2)

Asperi
Asperi

Reputation: 257703

Assuming ScooterExtension has a property id, it can be done as follows:

Toggle(isOn: Binding<Bool>(get:{ self.isOn }, 
                set: { 
                    self.isOn = $0
                    if $0 { 
                       self.extensionIDs.append(self.scooterExtension.id) 
                    } else {
                       self.extensionIDs = self.extensionIDs.filter { $0 != self.scooterExtension.id }
                    }
                })) {
    Text(scooterExtension.name)
}

Upvotes: 3

Ben
Ben

Reputation: 424

Ah, I see what you are saying in your comment. How about a new container type for the ids. Something like

class ExtensionID: Identifiable, ObservableObject {
    let id: Int
    var isOn: Bool = true

    init(id: Int) {
        self.id = id
    }
}

Then you can bind the Toggle to the isOn property and conditionally display the ScooterExtensionRow (or whatever other changes you need based on a given id being off instead of actually missing from the array) based on this as well.

Does this make any sense?

Upvotes: 0

Related Questions