0

How can I show data on a tableview with its origin from a struct and one extra cell for adding action?

All data(invoice and items) is fetched from a server and it works fine.

If I add a print, it shows all data on the console.

[Invoice.InvoiceItem(invoice_detail_id: 13, description: oi, unit_price: 2, quantity: 1), Invoice.InvoiceItem(invoice_detail_id: 14, description: re, unit_price: 3, quantity: 2), Invoice.InvoiceItem(invoice_detail_id: 15, description: fsdf, unit_price: 4, quantity: 3)]

The problem is that it doesnt populate on the tableview. I tried adding or subtracting 1 without success.

Also, there is one more cell, that is not for items, but for adding a new item, and always being the last cell or the only one when there is no item.

tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) seems to be called only once... where in fact it should be 4 (3 items plus add cell)

import UIKit

class InvoiceItemCell: UITableViewCell {
    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var unitPriceQuantityLabel: UILabel!
    @IBOutlet weak var lineTotalLabel: UILabel!

}

class InvoiceViewController: UIViewController, AccessoryToolbarDelegate,UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var dateIssueTextField: UITextField!
    @IBOutlet weak var dueDateTextField: UITextField!
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var taxDescriptionLabel: UILabel!

    var thePicker = UIDatePicker()
    var invoice: Invoice?
    var client: Client?
    var invoiceItems : [InvoiceItem] = [InvoiceItem]()

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        dateIssueTextField.delegate = self
        dueDateTextField.delegate = self

        self.thePicker = UIDatePicker(frame:CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 216))
        self.thePicker.backgroundColor = UIColor.white
        self.thePicker.datePickerMode = UIDatePickerMode.date

        //data will be loaded from an API to a server. Hard Coded now just for testing
        setUpTextFieldPicker(textField: dateIssueTextField)
        setUpTextFieldPicker(textField: dueDateTextField)

        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.rowHeight = 75

    }

    override func viewWillAppear(_ animated: Bool) {
        self.title = "New"
        taxDescriptionLabel.text = "Tax @ 0%"

        if (invoice?.invoice_id) != nil {
            self.title = "Edit"
            dueDateTextField.text = invoice?.due_date
            dateIssueTextField.text = invoice?.date_issue
            let taxDescription = invoice?.tax.description
            taxDescriptionLabel.text = "Tax @ \(taxDescription ?? "0")%"

            let invoiceItems = invoice?.items


            print("Will Appear")
            print(invoiceItems!)
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return invoiceItems.count + 1
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if ((indexPath as NSIndexPath).row == (invoiceItems.count)) {
            return 50
        } else {
            return 75
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        //if ((indexPath as NSIndexPath).row == (invoiceItems.count)) {
        print(indexPath.row)
        if (indexPath.row == (invoiceItems.count)) {
            let cell = tableView.dequeueReusableCell(withIdentifier: "InvoiceAddCell", for: indexPath)
            print("add cell")
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "InvoiceItemCell", for: indexPath) as! InvoiceItemCell
            let item = invoiceItems[indexPath.row]
            print("Cell")

            cell.descriptionLabel.text = item.description

            let partial = (item.unit_price?.description)!+" X "+(item.quantity?.description)!
            cell.unitPriceQuantityLabel.text = partial

            let lineTotal = item.unit_price * item.quantity
            cell.lineTotalLabel.text = lineTotal.description
            return cell
        }



    }


    func doneClicked(for textField: UITextField) {
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .short
        dateFormatter.timeStyle = .none

        //show on text field
        dateFormatter.dateFormat = "dd MMM yyyy"
        textField.text = dateFormatter.string(from: thePicker.date)

        //formated to store on mysql
        dateFormatter.dateFormat = "yyyy-MM-dd"
        let finalDate: String = dateFormatter.string(from: thePicker.date)
        print(finalDate)
        textField.resignFirstResponder()
    }

    func cancelClicked(for textField: UITextField) {
        textField.resignFirstResponder()
    }

    func setUpTextFieldPicker(textField: UITextField) {
        textField.inputView = thePicker
        let toolbar = AccessoryToolbar(for: textField)
        toolbar.accessoryDelegate = self
    }

    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd MMM yyyy"
        if let fullDate = dateFormatter.date(from: textField.text!) {
            thePicker.date = fullDate
        } else {
            thePicker.date = Date()
        }

        return true
    }



}

Structs

struct InvoiceItem: Codable {
    var invoice_detail_id: Int!
    let description: String!
    let unit_price: Decimal!
    let quantity: Decimal!

    init(invoice_detail_id: Int! = nil, description: String, unit_price: Decimal, quantity: Decimal) {
        self.invoice_detail_id = invoice_detail_id
        self.description = description
        self.unit_price = unit_price
        self.quantity = quantity
    }

}

//let invoiceItems = [InvoiceItem(invoice_detail_id: 1, description: "AB", unit_price: 10.22, quantity: 2),
//                    InvoiceItem(invoice_detail_id: 2, description: "fsdsdsdfsdf", unit_price: 44.35, quantity: 10)]

struct Invoice: Codable {
    var invoice_id: Int!
    let client_id: Int!
    let tax: Decimal!
    let date_issue: String!
    let due_date: String!
    let amount_paid: Decimal!
    let date_transaction: String!
    let voided: Int!
    let note: String!
    let invoice_number: String!
    let status: String!
    let items: [InvoiceItem]!

    init(invoice_id: Int! = nil, client_id: Int! = nil,tax: Decimal, date_issue: String, due_date: String, amount_paid: Decimal, date_transaction: String, voided: Int, note: String, invoice_number: String, status: String, items: InvoiceItem) {
        self.invoice_id = invoice_id
        self.client_id = client_id
        self.tax = tax
        self.date_issue = date_issue
        self.due_date = due_date
        self.amount_paid = amount_paid
        self.date_transaction = date_transaction
        self.voided = voided
        self.note = note
        self.invoice_number = invoice_number
        self.status = status
        self.items = [items]

    }
}
2
  • How does invoice get set to something other than nil? Commented Feb 24, 2018 at 18:32
  • From a prev view passing as a parameter. Commented Feb 24, 2018 at 18:51

1 Answer 1

1

The problem is with viewWillAppear. The local invoiceItems there is not the invoiceItems property used by the table view's data source.

Change it as follows:

override func viewWillAppear(_ animated: Bool) {
    self.title = "New"
    taxDescriptionLabel.text = "Tax @ 0%"

    if (invoice?.invoice_id) != nil {
        self.title = "Edit"
        dueDateTextField.text = invoice?.due_date
        dateIssueTextField.text = invoice?.date_issue
        let taxDescription = invoice?.tax.description
        taxDescriptionLabel.text = "Tax @ \(taxDescription ?? "0")%"

        invoiceItems = invoice?.items // No let

        print("Will Appear")
        print(invoiceItems!)
    }
}

And all of this code really should be in viewDidLoad, not viewWillAppear.

Sign up to request clarification or add additional context in comments.

1 Comment

It works! I use will appear because did load is called only when the view is created... I have a prev view with a list of invoices and when touch the cell, it calls this view passing the selected invoice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.