Search code examples
swiftlistswiftuiforeachradio-button

Facing issue in list radio button selection in swiftui


code: with this code i am able to select each question multi check boxes but when it comes selecting radio button selection then i can able to select any one question options... if i select another question option then before question selection removes why? how to select each question options

struct SurveyQuestionsView: View {
@Environment(\.dismiss) var dismiss
@StateObject private var viewModel = SurveyViewModel()
@State var id: String = ""
@State private var selectedOption: Int? = nil
@State private var selectedOptions: Set<Int> = []

var body: some View {
    ZStack {
        
        VStack(alignment: .leading) {
            
            Text("(*) Mandatory Questions")
                .font(.calibriRegular(with: 15))
                .foregroundStyle(.red)
                .padding()
            ScrollView{
                ForEach(0..<viewModel.questionsArray.count, id: \.self) {i in
                    questionOptionsCell(question: viewModel.questionsArray[i])
                    Rectangle()
                        .frame(height: 3)
                        .foregroundColor(Color.hexF4F4FC)
                }
            }
            
            Spacer()
        }
    }
    .onAppear{
        
        viewModel.fetchQuestionOptions(id: id) { status in
        }
    }
}
@ViewBuilder
func questionOptionsCell(question: QuestionSurvey) -> some View {
    VStack(alignment: .leading) {
        
        HStack {
            Text(question.question ?? "N/A")
                .font(.calibriRegular(with: 17))
                .foregroundStyle(.green)
                .padding(.leading, 10)
            if question.isMultiSelect ?? false {
                Text("*")
                    .foregroundColor(.red)
            }
        }
        
        ForEach(question.options ?? [], id: \.optID) { option in
            HStack {
                if question.isMultiSelect ?? false {
                    Image(systemName: selectedOptions.contains(option.optID!) ? "checkmark.square" : "square")
                        .onTapGesture {
                            if selectedOptions.contains(option.optID!) {
                                selectedOptions.remove(option.optID!)
                            } else {
                                selectedOptions.insert(option.optID!)
                            }
                        }
                } else {
                    Image(systemName: (selectedOption == option.optID ? "largecircle.fill.circle" : "circle"))
                        .onTapGesture {
                            if selectedOption != option.optID {
                                selectedOption = option.optID
                            }
                        }
                }
                
                Text(option.option ?? "Option")
                    .onTapGesture {
                        if question.isMultiSelect ?? false {
                            if selectedOptions.contains(option.optID!) {
                                selectedOptions.remove(option.optID!)
                            } else {
                                selectedOptions.insert(option.optID!)
                                print("selectedOption.... \(selectedOptions)")
                                
                            }
                        } else {
                            selectedOption = option.optID
                            print("selectedOption.... \(selectedOption)")
                        }
                    }
                Spacer()
            }
            .padding(.vertical, 5)
            .padding(.leading, 15)
        }
    }
}
}

o/p

enter image description here

edit: this is QuestionSurvey model

struct QuestionSurvey: Codable {
let queID: Int?
let question: String?
let isMultiSelect, isAnsMandatory: Bool?
let response: Int?
var options: [Option]?
}

tried like this still same issue

else {
       Image(systemName: (selectedOption == option.optID ? "largecircle.fill.circle" : "circle"))
       .onTapGesture {
                            selectedSingleOptions[question.queID ?? 0] = option.optID ?? 0
                      }
      }

Solution

  • If I understand correctly, the issue is that when you select an answer from the second question with radio buttons, the answer from the first question with radio buttons is de-selected.

    I was able to reproduce this by running your code (after improvising all the missing parts). The problem is happening because the id of the selected answer is stored in selectedOption, which effectively means, you only have one radio button group.

    To fix, you need to have one variable per radio button group. You could do this by using a dictionary, keyed by question id.

    Assuming that each question has an Int id:

    @State private var selectedSingleOptions = [Int: Int]()
    
    if question.isMultiSelect ?? false {
        // ...
    } else {
        Image(systemName: (selectedSingleOptions[question.id] == option.optID ? "largecircle.fill.circle" : "circle"))
            .onTapGesture {
                selectedSingleOptions[question.id] = option.optID ?? 0
            }
    }