I have collection view cell, and I have stepper and product name label inside the collection view cell. I have six products displayed on the collection view cell. I want to add the product to cart / order by tapping the Add To Cart Button.
once the add to cart button is tapped, then the add to cart button will be hided and it will show the stepper, like the image below.
here is my code for my collection view cell:
protocol OrderCellDelegate {
func stepperValueChange(at selectedIndexPath: IndexPath, stepperValue: Int)
}
class OrderCell: UICollectionViewCell {
@IBOutlet weak var stepper: GMStepper!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet var addToCartButton: UIButton!
var productData : Product? {
didSet {
updateUI()
}
}
var indexPath: IndexPath?
var delegate: OrderCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
setStepper()
}
@IBAction func addToCartButtonDidTapped(_ sender: Any) {
stepper.value = 1.0
}
@IBAction func stepperValueChanged(_ sender: Any) {
print("stepper value: \(stepper.value)")
guard let selectedIndexPath = indexPath else {return}
let value = Int(stepper.value)
self.delegate?.stepperValueChange(at: selectedIndexPath, stepperValue: value)
}
func setStepper() {
stepper.autorepeat = false
stepper.minimumValue = 0
stepper.maximumValue = 100
stepper.stepValue = 1.0
}
func updateUI() {
guard let product = productData else {return}
nameLabel.text = product.name
setCartAndStepperButton()
}
private func setCartAndStepperButton() {
guard let selectedProduct = productData else {return}
func showStepperButton(status: Bool) {
// to decide whether to show stepper or add to cart button.
stepper.isHidden = !status
stepper.isEnabled = status
addToCartButton.isHidden = status
addToCartButton.isEnabled = !status
}
if selectedProduct.quantityInCart == 0 {
showStepperButton(status: false)
} else {
showStepperButton(status: true)
}
}
}
as you can see in the addToCartButtonDidTapped
method above, I set the stepper value to be 1 programmatically, I expect the number in the blue stepper above to be 1, but it shows zero instead of one (like the screenshot above)
I connect the stepperValueChanged
method using @IBAction using 'value change' as the sent event. so when the stepper.value = 1.0
is triggered inside addToCartButtonDidTapped
, then all the code inside stepperValueChanged
method will automatically triggered
but why it become zero even though I force it to be one ? could you please help me with this one ?
here is the file project in google drive: https://drive.google.com/file/d/1VBR0HkR2Wb2RF2m1CC3zI8a5hJipHW7W/view
here is my view controller code:
class ViewController: UIViewController, OrderCellDelegate {
@IBOutlet weak var collectionView: UICollectionView!
var order : Order!
var allProducts = [Product]()
override func viewDidLoad() {
super.viewDidLoad()
order = Order.getOrderFromRealmDatabase()
allProducts = Product.fetchProductData()
}
func stepperValueChange(at selectedIndexPath: IndexPath, stepperValue: Int) {
guard let userOrder = order else {return}
let selectedProduct = allProducts[selectedIndexPath.item]
let maximumQuantityOfProduct = 100
let minimumQuantityOfProduct = 1
if stepperValue == minimumQuantityOfProduct - 1 {
// remove the product from the cart if the stepper value is one below the minimum allowable quantity
Order.removeProductFromOrderRealmDatabase(userOrder: userOrder, selectedProduct: selectedProduct)
Product.changeProductQuantityInRealmDatabase(selectedProduct: selectedProduct, quantity: 0)
} else if stepperValue == minimumQuantityOfProduct {
// it means add to cart button is tapped
if userOrder.products.filter("productID == %@", selectedProduct.productID).first == nil {
Order.addProductToOrderRealmDatabase(userOrder: userOrder, selectedProduct: selectedProduct)
} else {
Order.removeProductFromOrderRealmDatabase(userOrder: userOrder, selectedProduct: selectedProduct)
}
} else if stepperValue > minimumQuantityOfProduct && stepperValue <= maximumQuantityOfProduct {
Product.changeProductQuantityInRealmDatabase(selectedProduct: selectedProduct, quantity: stepperValue)
}
collectionView.reloadData()
}
}
// DATA SOURCE
extension ViewController : UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return allProducts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "orderCell", for: indexPath) as! OrderCell
cell.productData = allProducts[indexPath.item]
cell.delegate = self
cell.indexPath = indexPath
return cell
}
}
and here is the product code:
import RealmSwift
class Product : Object {
@objc dynamic var productID : Int = 0
@objc dynamic var name : String = ""
@objc dynamic var unitPrice: Double = 0.0
@objc dynamic var quantityInCart : Int = 0
@objc dynamic var descriptionProduct : String = ""
@objc dynamic var hasBeenAddedToCart : Bool = false
override static func primaryKey() -> String? {
return "productID"
}
convenience init(productID: Int, name: String, unitPrice: Double, descriptionProduct: String) {
self.init()
self.productID = productID
self.name = name
self.unitPrice = unitPrice
self.descriptionProduct = descriptionProduct
}
static func fetchProductData() -> [Product] {
let product1 = Product(productID: 1, name: "Product1", unitPrice: 1000, descriptionProduct: "Description of Product 1")
let product2 = Product(productID: 2, name: "Product2", unitPrice: 2000, descriptionProduct: "Description of Product 2")
let product3 = Product(productID: 3, name: "Product3", unitPrice: 3000, descriptionProduct: "Description of Product 3")
let product4 = Product(productID: 4, name: "Product4", unitPrice: 4000, descriptionProduct: "Description of Product 4")
let product5 = Product(productID: 5, name: "Product5", unitPrice: 5000, descriptionProduct: "Description of Product 5")
let product6 = Product(productID: 6, name: "Product6", unitPrice: 6000, descriptionProduct: "Description of Product 6")
return [product1,product2,product3,product4,product5,product6]
}
static func changeProductQuantityInRealmDatabase(selectedProduct: Product, quantity: Int) {
guard let selectedProductInRealmDatabase = RealmService.shared.realm.objects(Product.self).filter("productID == %@", selectedProduct.productID).first else {return}
RealmService.shared.updateOnCertainKey(object: selectedProductInRealmDatabase, for: ["quantityInCart": quantity])
}
}
here is the order model:
class Order : Object {
@objc dynamic var userID: String = ""
var products = List<Product>()
convenience init (userID: String, products: List<Product>) {
self.init()
self.userID = "1"
self.products = products
}
//MARK: - Realm Related
static func getOrderFromRealmDatabase() -> Order {
let userID = "1"
let realmService = RealmService.shared.realm
let allOrder = realmService.objects(Order.self)
let theOrder = allOrder.filter("userID CONTAINS[cd] %@", userID).first
if let userOrder = theOrder {
return userOrder
} else {
// Order never setted up before in Realm database container
// then create Order in realm database
let newOrder = Order()
newOrder.userID = userID
newOrder.products = List<Product>()
RealmService.shared.save(object: newOrder)
return newOrder
}
}
static func addProductToOrderRealmDatabase(userOrder: Order, selectedProduct: Product) {
// check if the selected product has already available in Product.self database or not
if let matchingProduct = RealmService.shared.realm.objects(Product.self).filter("productID == %@", selectedProduct.productID).first {
RealmService.shared.save(expression: {
userOrder.products.append(matchingProduct)
matchingProduct.hasBeenAddedToCart = true
matchingProduct.quantityInCart += 1
})
} else {
RealmService.shared.save(expression: {
userOrder.products.append(selectedProduct)
selectedProduct.hasBeenAddedToCart = true
selectedProduct.quantityInCart += 1
})
}
}
static func removeProductFromOrderRealmDatabase(userOrder: Order, selectedProduct: Product) {
// to check wheter the selected product from user is already in Order or not
if let matchingProduct = userOrder.products.filter("productID == %@", selectedProduct.productID).first {
RealmService.shared.save(expression: {
matchingProduct.hasBeenAddedToCart = false
guard let index = userOrder.products.index(where: {$0.productID == matchingProduct.productID}) else {return}
userOrder.products.remove(at: index)
matchingProduct.quantityInCart -= 1
})
}
}
}