Asim Roy
Asim Roy

Reputation: 10226

Preventing toggle switch on and showing alert in Swiftui

I have some Toggle Switches in a row but I want to prevent switches ON if already two of them is ON. And showing an Alert that maximum 2 of them is allowed to ON. Here is my code:

struct PreventToggle: View {

    @State private var isCheckeds = [false, true, true, false, false, false]
    @State var showAlert = false

    var body: some View {

        let numberOfTrue = isCheckeds.filter{$0}.count
        showAlert = numberOfTrue > 2

        return ForEach(0 ..< isCheckeds.count) { id in

                Toggle("Switch \(id)", isOn: self.$isCheckeds[id])
                    .alert(isPresented: self.$showAlert) {
                        Alert(title: Text("Maximum Limit!"), message: Text("Maximum limit is: 3"), dismissButton: .default(Text("Got it")))
                }
        }
    }
}

enter image description here

Upvotes: 3

Views: 1566

Answers (2)

nine stones
nine stones

Reputation: 3438

This is how it can work:

struct PreventToggle: View {
  @State private var isCheckeds = [false, true, true, false, false, false]
  @State var lastSelected = -1

  func alertBinding() -> Binding<Bool> {
    Binding<Bool>(
      get: {
        let numberOfTrue = self.isCheckeds.filter{$0}.count
        return numberOfTrue > 2 && self.lastSelected != -1
      },
      set: { _ in }
    )
  }

  func toggleBinding(for index: Int) -> Binding<Bool> {
    Binding<Bool>(
      get: {
        return self.isCheckeds[index]
      },
      set: { bool in
        self.isCheckeds[index] = bool
        self.lastSelected = index
      }
    )
  }

  var body: some View {
    VStack {
      ForEach(0 ..< isCheckeds.count) { id in
        Toggle("Switch \(id)", isOn: self.toggleBinding(for: id))
      }
    }
    .alert(isPresented: alertBinding()) {
      Alert(title: Text("Maximum Limit!"),
            message: Text("Maximum limit is: 3"),
            dismissButton: .default(Text("Got it"), action: {
              self.isCheckeds[self.lastSelected] = false
              self.lastSelected = -1
            })
      )
    }
  }
}

Upvotes: 3

Chris
Chris

Reputation: 8126

try this:

...but then the message never disappears, because you never set the toggle values back to 2...so this is what you still have to do. and maybe you should do your check inside the toggle action and not when building the view.

struct ContentView: View {

    @State private var isCheckeds = [false, true, true, false, false, false]
    @State var showAlert = false

    var body: some View {

        let numberOfTrue = isCheckeds.filter{$0}.count
        OperationQueue.main.addOperation {
            self.showAlert = numberOfTrue > 2
        }

        return VStack {
            ForEach(0 ..< isCheckeds.count) { id in

                Toggle("Switch \(id)", isOn: self.$isCheckeds[id])
                    .alert(isPresented: self.$showAlert) {
                        Alert(title: Text("Maximum Limit!"), message: Text("Maximum limit is: 3"), dismissButton: .default(Text("Got it")))
                }
            }
        }
    }
}

Upvotes: -1

Related Questions