0

I have a main view model called CustomizeMenuItemViewModel which has a property maxItemCount which needs to be decreased to 0 whenever the user interacts with the view to add one item in the shopping bag. The view interacts with its own view model called CustomizationQuantityCellViewModel which is instantiated from the main view model. I cannot find a way to bind the property maxItemCount to the view interaction which has CustomizationQuantityCellViewModel in between.

Relevant Code:

final class CustomizeMenuItemViewModel {
    private(set) var item: MenuItem
    @Binding private(set) var maxUnitCount: Int

    // MARK: - Initializer
    init(item: MenuItem) {
        self.item = item
        _maxUnitCount = .constant(0)
    }

    func menuItem(option: Option, index: Int) -> MenuItemCellType {
        let selections = Array(option.selections)
        if option.multiselect {
            if option.max > 0 {
                maxUnitCount = option.max
                return .quantity(CustomizationQuantityCellViewModel(selection: selections[index], maxUnit: $maxUnitCount), (index != selections.count - 1))
            } else {
                return .checkbox(CustomizationMenuItemCellViewModel(selection: selections[index]), (index != selections.count - 1))
            }
        } else {
            if option.name.lowercased().contains("bun") {
                return .card(CustomizationMenuItemCellViewModel(selection: selections[index]), (index != selections.count - 1))
            } else if option.max > 0 {
                maxUnitCount = option.max
                return .quantity(CustomizationQuantityCellViewModel(selection: selections[index], maxUnit: $maxUnitCount), (index != selections.count - 1))
            } else {
                return .radiobutton(CustomizationMenuItemCellViewModel(selection: selections[index]), (index != selections.count - 1))
            }
        }
    }
}
final class CustomizationQuantityCellViewModel: ObservableObject {
    // MARK: - Properties
    private(set) var selection: Selection
    @Binding private(set) var maxUnit: Int
    @Published private(set) var selectedUnits: Int
    // MARK: - Initializer
    init(selection: Selection, maxUnit: Binding<Int>) {
        self.selection = selection
        self._maxUnit = maxUnit
        self.selectedUnits = 0
    }

    func increaseSelectedUnit() {
        if maxUnit > 0 {
            selectedUnits += 1
            maxUnit -= 1
        }
    }

    func decreseSelectedUnit() {
        if selectedUnits > 0 {
            selectedUnits -= 1
            maxUnit += 1
        }
    }
}

struct CustomizationQuantityCell: View {
    // MARK: - Properties
    @ObservedObject private var viewModel: CustomizationQuantityCellViewModel

    // MARK: - Initializer
    init(viewModel: CustomizationQuantityCellViewModel) {
        self.viewModel = viewModel
    }

    // MARK: - Body
    var body: some View {
        VStack {
            HStack(spacing: 16) {
                Text(viewModel.selection.name)
                    .font(.system(size: 16))
                    .foregroundColor(Color(Colors.brown500.color))
                    .padding(.top, 20)
                    .padding(.bottom, 20)
                Spacer()
                HStack(spacing: 32) {
                    Button {
                        viewModel.decreseSelectedUnit()
                    } label: {
                        Image(Images.minus.name)
                    }
                    .buttonStyle(.plain)
                    Text("\(viewModel.selectedUnits)")
                        .font(.system(size: 15))
                        .foregroundColor(Color(Colors.brown500.color))
                    Button {
                        viewModel.increaseSelectedUnit()
                    } label: {
                        Image(Images.plus.name)
                    }
                    .buttonStyle(.plain)
                }
            }
           
        }
    }
}

I tried the above approach but the binding always set 0 to maxUnitCount.

  • View Models should never know anything about each other, if they need to access common data that data should be moved down to a manager/store – lorem ipsum Nov 29 '22 at 18:23
  • you should learn `@State` and `@Binding` which makes the View struct behave like an object so you don't need separate view model objects. – malhal Nov 29 '22 at 20:13

1 Answers1

0

Just remove your binding from your maxUnitcount and make that view model ObservableObject.

final class CustomizeMenuItemViewModel: ObservableObject {
    private(set) var item: MenuItem
    @Published private(set) var maxUnitCount: Int

And the other thing you need to change is your the other viewmodel. It will work.

final class CustomizationQuantityCellViewModel: ObservableObject {
    // MARK: - Properties
    private(set) var selection: Selection
    private(set) var maxUnit: Int
    private(set) var selectedUnits: Int
    // MARK: - Initializer
    init(selection: Selection, maxUnit: Int) {
        self.selection = selection
        self._maxUnit = maxUnit
        self.selectedUnits = 0
    }
}
Volkan Sonmez
  • 745
  • 3
  • 14