4

I have a View with many Buttons and if the User tap on a Button the Viewmodel need to update the current Button with the increased value.

class ProductVM: ObservableObject {
    @Published var product : Product


    init(product: Product) {
        self.product = product
    }


    public func increaseAmount() {
        var myInt = Int(self.product.amount) ?? 0
        myInt += 1
        self.product.amount = String(myInt)

        print(myInt)
        print("...")
    }
}

the problem is the myInt is every time just 1 and the value can't be updated.

HOW can i update the value and save it in the current Model so that the View know its increased ??!!

struct singleButtonView: View {
@ObservedObject var productVM : ProductVM




func updatePos(){
    self.productVM.increaseAmount()
  }
 }

and i call it with

singleButtonView(productVM: ProductVM(product: product))
xyzcodeeee
  • 161
  • 2
  • 13

1 Answers1

10

Nested ObservableObjects need to be updated manually. Here is an example how this could look like:

class Product: ObservableObject, Identifiable, Codable {
    let id: Int
    let name: String
    let prize: Double
    @Published var amount: Int = 0

    enum CodingKeys: String, CodingKey {
        case id
        case name
        case prize
        case amount
    }

    init() {
        self.id = 0
        self.name = "name"
        self.prize = 0
    }

    init(id: Int, name: String, prize: Double) {
        self.id = id
        self.name = name
        self.prize = prize
    }

    required init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)

        id = try values.decode(Int.self, forKey: .id)
        name = try values.decode(String.self, forKey: .name)
        prize = try values.decode(Double.self, forKey: .prize)
        amount = try values.decode(Int.self, forKey: .amount)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(name, forKey: .name)
        try container.encode(prize, forKey: .prize)
        try container.encode(amount, forKey: .amount)
    }
}


class ProductVM: ObservableObject {
    @Published var product: Product
    var cancelable: AnyCancellable? = nil

    init(product: Product) {
        self.product = product
        self.cancelable = product.objectWillChange.sink(receiveValue: {
            self.objectWillChange.send()
        })
    }

    public func increaseAmount() {
        self.product.amount += 1
    }
}


struct ContentView: View {
    @ObservedObject var productVM = ProductVM(product: Product())

    var body: some View {
        VStack {
            Button(action: {
                self.productVM.increaseAmount()
            }) {
                Text("Add")
            }
            Text("\(self.productVM.product.amount)")
        }
    }
}

I hope this helps! Credits

krjw
  • 4,070
  • 1
  • 24
  • 49
  • how can i fill the product class with the values of my product struct ? – xyzcodeeee Dec 12 '19 at 17:47
  • Which values? You could bind the @Published variables to the UI for example TextField – krjw Dec 12 '19 at 18:07
  • how do i call it right now ? my Product looks like -> struct Product : Identifiable, Decodable { let id: Int let name: String let prize: Double var amount: Int } – xyzcodeeee Dec 12 '19 at 22:18
  • 1
    Like I showed you... change your product strict to a class, inherit from ObservableObject and add the @Published property wrapper... then add what I have in the ProductVM – krjw Dec 13 '19 at 07:34
  • 1
    @xyzcodeeee I added what you asked for in the `Product` class – krjw Dec 13 '19 at 11:28
  • no problem! Did this answer your question or do you still have a problem with the solution? – krjw Dec 13 '19 at 22:19
  • 1
    i have still other problems with it. but this question is fixed right now. – xyzcodeeee Dec 13 '19 at 22:56
  • can i contact you private here or at other pages ? – xyzcodeeee Dec 13 '19 at 22:57
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/204235/discussion-between-krjw-and-xyzcodeeee). – krjw Dec 13 '19 at 23:00