1

My project is creating an ordering app, and in this screen about the menu detail, there are menu variants which users can choose / add-on, I need to iterate an array of [MenuDetailVariantGroup] and I need to get the index of the array, how do I do this? While in the for loop I also need to append a variable into a @Published var variantChosen, however if I do self.viewModel.variantChosen.append(1), it always returns an error. Below is my codes:

MenuDetailData.swift

struct MenuDetailData: Codable, Identifiable {
    let id = UUID()
    let idMenu: String
    let menuName: String
    let variantGroup: [MenuDetailVariantGroup]
}

MenuDetailVariantGroup.swift

struct MenuDetailVariantGroup: Codable, Identifiable, Hashable {
    let id = UUID()
    let variantGroupName: String
    let variant: [MenuDetailVariant]
    let limit: Int
}

MenuDetailVariant.swift

struct MenuDetailVariant: Codable, Identifiable, Hashable {
    let id = UUID()
    let variantName: String
}

MenuDetailViewModel.swift

class MenuDetailViewModel: ObservableObject, MenuDetailService {
    var apiSession: APIService
    @Published var detaildata: MenuDetailData?
    @Published var variantGroup = [MenuDetailVariantGroup]()
    @Published var variantChosen: Array<Int> = []
    
    var cancellables = Set<AnyCancellable>()
    
    init(apiSession: APIService = APISession()) {
        self.apiSession = apiSession
    }
    
    func getMenuDetail() {
        let cancellable = self.getMenuDetail()
            .sink(receiveCompletion: { result in
                switch result {
                case .failure(let error):
                    print("Handle error: \(error)")
                case .finished:
                    break
                }
                
            }) { (detail) in
                self.detaildata = detail.data
                self.variantGroup = detail.data.variantGroup
        }
        cancellables.insert(cancellable)
    }
    
}

MenuDetailView

struct MenuDetailView: View {
    @ObservedObject var viewModel = MenuDetailViewModel()
    
    var body: some View {
        ForEach(self.viewModel.variantGroup, id: \.self) { vg in
                /*** I Need to get the index of each iteration here, how? ***/
                VStack {
                    HStack {
                        Text(vg.variantGroupName)
                        Text(String(self.viewModel.arrVariantChoosen[0]))
                    }
                    VStack {
                        ForEach(vg.variant, id: \.self) { v in
                            Text(v.variantName)
                        }
                    }
                }
                // I also need to append Int to @Published var variantChosen
                self.viewModel.variantChosen.append(1)
                // This always return error:
                // Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols
            }
        }
    }
}

This is the codes that I have tried so far but failed and return empty

// This returns blank
ForEach(0..<self.viewModel.variantGroup.count) { i in
    Text("\(self.viewModel.variantGroup[i].variantGroupName)")
}

// This too returns blank
ForEach(self.viewModel.variantGroup.indices) { i in
    Text("\(self.viewModel.variantGroup[i].variantGroupName)")
}

Thank you all in advance

pawello2222
  • 46,897
  • 22
  • 145
  • 209
Charas
  • 1,753
  • 4
  • 21
  • 53
  • What you have tried should work fine, see [this answer](https://stackoverflow.com/a/57244880/9223839) for instance. Maybe the array is empty? You have a method `getMenuDetail` in your view model but is it ever called? – Joakim Danielson Jan 12 '21 at 12:24
  • It does get called, with the current "ForEach(self.viewModel.variantGroup, id: \.self) { vg in" returns the data, but I could not get the index, weirdly with the "ForEach(0.. – Charas Jan 12 '21 at 12:26
  • Also why is that method calling itself? But maybe you should ignore that function for now and hardcode some values into the `variantGroup` array and see if you can get the `ForEach` to work, that way you deal with one problem at a time. – Joakim Danielson Jan 12 '21 at 12:30

1 Answers1

3

You can use enumerated to have both index and element, like

    var body: some View {
        ForEach(Array(self.viewModel.variantGroup.enumerated()), id: \.1) { index, vg in
                /*** I Need to get the index of each iteration here, how? ***/
                VStack {
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Thanks you so much man, this does work, how do I append the value to the array in the ViewModel @Published var variantChosen in the foreach loop though? – Charas Jan 12 '21 at 12:46