2

I have 2 ViewControllers, one of is called ProductListVC the other is MoreInfoVC. I have a tableView on ProductListViewController that shows cells multiple labels and buttons.

MoreInfoVC is a Modal pop-up VC with a few labels for the brand, Name, and description. I have all my data stored in Firestore and already have created class(ProductList) to help retrieve the data which presents the data in the tableview from the Cloud Firestore.

what I need to do is use the MoreInfo button in the individual TBV cell to pass the data into MoreInfoVC so that it can present the information of selected product

Now i can easily do this with either didSelectRowAt method or using indexPathForSelectedRow in prepare segue method. But both cases requires me to tap on the cell itself but not the button.

how would I be able to pass data from an individual tableview cell through the MoreInfo button onto the MoreInfoVC. I think I'm on the right path since it seems my MoreInfoVC is passing data but showing this at the moment


    import UIKit
    import Firebase
    import FirebaseFirestore

    class ProductListVC: UIViewController {

        @IBOutlet weak var productListTableView: UITableView!

        var productInventory: [ProductList] = []
        var productSetup: [ProductList] = []

        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
        }

        override func viewDidLoad() {
            super.viewDidLoad()

            productListTableView.dataSource = self
            productListTableView.delegate = self
            searchBar.delegate = self

            fetchProducts { (products) in
                self.productSetup = products
                self.productListTableView.reloadData()
            }

        }
       func fetchProducts(_ completion: @escaping ([ProductList]) -> Void) {
           let ref = Firestore.firestore().collection("products")
      ref.addSnapshotListener { (snapshot, error) in
                guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
                    return
                }
                completion(snapshot.documents.compactMap( {ProductList(dictionary: $0.data())} ))
            }
        }
    }

    extension ProductListVC: UITableViewDelegate, UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

            return productSetup.count
        }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as?
    ProductListCell else { return UITableViewCell() }

             cell.configure(withProduct: productSetup[indexPath.row])

             cell.delegate = self

          return cell
      }

  }

  extension ProductListVC: ProductListCellDelegate {
      func onTouchInfoButton(from cell: ProductListCell) {
          self.selectedProduct = cell.product
      }

      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
          self.performSegue(withIdentifier: "MoreInfo", sender: self)
      }
 }

   import UIKit
   import Firebase

   class MoreInfoVC: UIViewController {

        var products: ProductList?

        @IBOutlet weak var productName: UILabel!

        override func viewDidLoad() {
             super.viewDidLoad()

           // Do any additional setup after loading the view.

           productName.text = "\(String(describing: products?.brand)): \(String(describing: products?.name))"
       }

       @IBAction func closeBtn(_ sender: Any) {
            dismiss(animated: true, completion: nil)
            print("Close More Information")
       }
   }

  import UIKit
  import SDWebImage
  import Firebase

  protocol ProductListCellDelegate: class {
      func onTouchInfoButton(from cell: ProductListCell)
  }

  class ProductListCell: UITableViewCell {

      weak var product: ProductList!
      weak var delegate: ProductListCellDelegate?

      @IBOutlet weak var productImage: UIImageView!
      @IBOutlet weak var productName: UILabel!
      @IBOutlet weak var categoryLabel: UILabel!
      @IBOutlet weak var strain: UILabel!

      @IBOutlet weak var moreInfo: RoundButton!

      func configure(withProduct product: ProductList) {
          productName.text = "\(String(describing: product.brand)): \(String(describing: product.name))"
          categoryLabel.text = product.category
          productImage.sd_setImage(with: URL(string: product.imageUrl))
          strain.text = product.strain

          self.product = product
      }

      @IBAction func infoButtonAction(_ sender: Any) {
          self.delegate?.onTouchInfoButton(from: self)
      }
  }
Evelyn
  • 186
  • 1
  • 4
  • 25

1 Answers1

3

Function @IBAction func infoButtonAction(_ sender: Any) {} should be in the ProductListCell

When that button is tapped, connect with the ProductListVC by delegate or closure to get the selected product.

Update

Using delegate: Update your ProductListCell

import UIKit
import SDWebImage
import Firebase

protocol ProductListCellDelegate: class {
    func onTouchInfoButton(from cell: ProductListCell)
}

class ProductListCell: UITableViewCell {

      @IBOutlet weak var productImage: UIImageView!
      @IBOutlet weak var dispensaryName: UILabel!
      @IBOutlet weak var productName: UILabel!
      @IBOutlet weak var thcPercent: UILabel!
      @IBOutlet weak var cbdPercent: UILabel!
      @IBOutlet weak var categoryLabel: UILabel!
      @IBOutlet weak var categoryStrain: UILabel!

      @IBOutlet weak var moreInfo: RoundButton!
      weak var product: Product!
      weak var delegate: ProductListCellDelegate?

      func configure(withProduct product: ProductList) {
          self.product = product
          productName.text = "\(String(describing: product.brand)): \(String(describing: product.name))"
          dispensaryName.text = product.dispensaryName
          categoryLabel.text = product.category
          productImage.sd_setImage(with: URL(string: product.imageUrl))
          cbdPercent.text = product.cbd
          thcPercent.text = product.thc
          categoryStrain.text = product.strain
      }

      @IBAction func infoButtonAction(_ sender: Any) {
          self.delegate?.onTouchInfoButton(from: self)
      }
}

In your ProductListVC:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as?
    ProductListCell else { return UITableViewCell() }

    cell.configure(withProduct: productSetup[indexPath.row])

    cell.delegate = self

    return cell
}

extension ProductListVC: ProductListCellDelegate {
     func onTouchInfoButton(from cell: ProductListCell) {
        let selectedProduct = cell.product
        // Do your stuff here 
     }
}

UPDATE

Because you use segue for navigation so let's create a variable to store your selected product in your ProductListVC

import UIKit
    import Firebase
    import FirebaseFirestore

    class ProductListVC: UIViewController {

        @IBOutlet weak var productListTableView: UITableView!

        var productInventory: [ProductList] = []
        var productSetup: [ProductList] = []
        var selectedProduct: Product?

        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
        }

        override func viewDidLoad() {
            super.viewDidLoad()

            productListTableView.dataSource = self
            productListTableView.delegate = self
            searchBar.delegate = self

            fetchProducts { (products) in
                self.productSetup = products
                self.productListTableView.reloadData()
            }

        }
       func fetchProducts(_ completion: @escaping ([ProductList]) -> Void) {
           let ref = Firestore.firestore().collection("products")
      ref.addSnapshotListener { (snapshot, error) in
                guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
                    return
                }
                completion(snapshot.documents.compactMap( {ProductList(dictionary: $0.data())} ))
            }
        }

            override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if let vc = segue.destination as? MoreInforVC {
            vc.product = self.selectedProduct
            }
        }
    }

    extension ProductListVC: UITableViewDelegate, UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

            return productSetup.count
        }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as?
    ProductListCell else { return UITableViewCell() }

             cell.configure(withProduct: productSetup[indexPath.row])

             cell.delegate = self

          return cell
      }

  }

  extension ProductListController: ProductListCellDelegate {
      func onTouchInfoButton(from cell: ProductListCell) {
          self.selectedProduct = cell.product
          self.performSegue(withIdentifier: "YourSegueIdentifier", sender: self)
      }
  }
jacob
  • 1,024
  • 9
  • 14
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/200623/discussion-on-answer-by-jacob-how-pass-data-from-button-in-tableviewcell-to-view). – Samuel Liew Oct 09 '19 at 23:46