LAST CHANCE: Save 50% on all my Swift books and bundles! >>

List not updated after adding a new item

Forums > SwiftUI

Hi everyone,

List not updated after adding a new item

struct HistoryIView: View {

    @StateObject var historyData1 = historyData()

    private var totalAmount: Double {
        historyData1.item.reduce(0.0) { partialResult, item in
            partialResult + item.price
            // also can be expressed as { $0 + $1.amount }
        }
    }

    var body: some View {
        NavigationView {
            List {
                Section(header: Text("Invoice History \(totalAmount.formatted(.currency(code: Locale.current.currency?.identifier ?? "BD")))")) {

                    ForEach(historyData1.item, id: \.id) { it in
                        HStack {
                            VStack(alignment: .leading) {

                                Text(it.cus)

                                Text(it.cusNum)

                                Text(it.dat.formatted(date: .abbreviated, time: .shortened))
                                    .foregroundColor(Color("grayed"))
                            }
                            Spacer()
                            VStack {
                                HStack {
                                    Text("Recipt#:")
                                        .foregroundColor(.red)

                                    Text("\(it.invNum)")
                                }

                                Text(it.price, format: .currency(code: Locale.current.currency?.identifier ?? "BD"))
                                    .foregroundColor(.green)
                            }
                        }
                    }
                    .onDelete(perform: removeItem)
                }
            }
            .navigationTitle("Invoice history")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Delete All") {
                        historyData1.item.removeAll()
                    }
                    .tint(.red)
                }
            }
        }
    }

    func removeItem(at offsets: IndexSet) {
        itemsData.items.remove(atOffsets: offsets)
    }
}

How to fix that?

Thanks in Advance

2      

Hi there! Where and how do you add item here? In your struct you have only option for delete...

2      

Hi @ygeras , add from invoiceView :

Button("Save")  {
       let item = HistoryData(storN: storeName, storNum: contactNumber, invNum: invoiceNumber, dat: invoiceDate, cus: customerName, cusAddr: customerAddress, cusNum: cusContactNumber, price: totalAmount)

       historyData.item.insert(item, at: 0)
                        }

this is model :

struct HistoryData: Identifiable, Codable {
    var id = UUID()
    let storN: String
    let storNum: String
    let invNum: String
    let dat: Date
    let cus: String
    let cusAddr: String
    let cusNum: String
    let price: Double
}

class historyData: ObservableObject {
    @Published var item: [HistoryData] = [] {

        // FOR STORE DATA IN THE UserDefaults.
        didSet {
            let encoder = JSONEncoder()

            if let encode = try? encoder.encode(item) {
                UserDefaults.standard.set(encode, forKey: "HistoryData")

            }
        }
    }
    // FOR LOAD DATA FROM UserDefaults.
    init() {
        if let savedItems = UserDefaults.standard.data(forKey: "HistoryData") {
            if let decodedItems = try? JSONDecoder().decode([HistoryData].self, from: savedItems) {
                item = decodedItems
                return
            }
        }

        item = []
    }
}

2      

pls share your invoiceView.

2      

InvoiceView:

struct InvoiceView: View {

    // class.
    @StateObject var itemsData = ItemsData()

    @AppStorage("storeName") private var storeName = ""

    @AppStorage("invoiceNumber") private var invoiceNumber = ""

    @AppStorage("contactNumber") private var contactNumber = ""

    @State private var invoiceDate = Date()

    @AppStorage("customerName") private var customerName = ""

    @AppStorage("customerAddress") private var customerAddress = ""

    @AppStorage("cusContactNumber") private var cusContactNumber = ""

    @State private var showingAddItem = false

    @State private var showingHistoryView = false

    // FOR IMAGE PICKER.
    @State private var selectedItem: PhotosPickerItem? = nil
    @State private var selectedImageData: Data? = nil

    // FOR CALCULATE TOTAL AMOUNT.
    private var totalAmount: Double {
        itemsData.items.reduce(0.0) { partialResult, item in
            partialResult + item.price
            // also can be expressed as { $0 + $1.amount }
        }
    }

    // FOR CALCULATE DISCOUNT AMOUNT. (READING FROM AddView)
    private var discountAmount: Double {
        itemsData.items.reduce(0.0) { partialResult, item in
            partialResult + item.discountAmount
            // also can be expressed as { $0 + $1.amount }
        }
    }

    // FOR CALCULATE VAT AMOUNT.
    private var vatAmount1: Double {
        itemsData.items.reduce(0.0) { partialResult, item in
            if item.vat > 0 {
                let netAmount = item.price / (1 + item.vat/100)
                let vatamount = item.price - netAmount
                return partialResult + vatamount
            }
            return partialResult
        }
    }

    @State private var paymentM = "Cash"

    let paymentsList = ["Cash", "BenefitPay", "Debit Card"]

    @ObservedObject var historyData: historyData

//    @ObservedObject var totalPrice: TotalPrices

    @State private var type = "Income"

    @ObservedObject var expenses: Expenses

    var body: some View {
        NavigationView {
            List {
                // FOR IMAGE PICKER.
                PhotosPicker(
                    selection: $selectedItem,
                    matching: .images,
                    photoLibrary: .shared()) {
                        Text("Select a logo")
                    }
                    .onChange(of: selectedItem) { newItem in
                        Task {
                            // Retrieve selected asset in the form of Data
                            if let data = try? await newItem?.loadTransferable(type: Data.self) {
                                selectedImageData = data
                            }
                        }
                    }
                Group {
                    Section {
                        if let selectedImageData,
                           let uiImage = UIImage(data: selectedImageData) {
                            Image(uiImage: uiImage)
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .scaledToFit()
                                .frame(width: 200, height: 200)
                                .cornerRadius(200)
                        }
                    }
                }

                Section(header: Text("Store Details")) {
                    TextField("Store Name", text: $storeName)

                    TextField("Invoice number", text: $invoiceNumber)

                    TextField("contact number", text: $contactNumber)
                }

                Section{
                    DatePicker("Date", selection: $invoiceDate)
                }

                Section(header: Text("Customer Details")) {

                    TextField("Customer Name", text: $customerName)

                    TextField("Customer Address", text: $customerAddress)

                    TextField("contact number", text: $cusContactNumber)

                }
                Group {
                    // Add Item button
//                    Section {
                        Button{
                            showingAddItem = true
                        } label: {
                            HStack {
                                Image(systemName: "plus")
                                Text("Add Item")
                            }

                        }
                        .sheet(isPresented: $showingAddItem) {
                            AddView(ItemsData: itemsData)
                        }
//                    }

                    ForEach(itemsData.items, id: \.id) { item in
                        HStack {
                            VStack(alignment: .leading) {

                                Text(item.name)
                                    .lineLimit(3)

                                Text("x\(item.quantity.formatted())")
                                    .foregroundColor(Color("grayed"))
                            }
                            Spacer()

                            VStack {
                                Text(item.price, format: .currency(code: Locale.current.currency?.identifier ?? "BD"))
                                    .lineLimit(3)
                            }
                        }
                    }
                    .onDelete(perform: removeItem)
                }

                HStack {
                    Text("Discount amount")
                    Spacer()
                    Text("\(discountAmount.formatted(.currency(code: Locale.current.currency?.identifier ?? "BD")))")
                        .foregroundColor(.blue)
                }

                HStack {
                    Text("VAT amount")
                    Spacer()
                    Text("\(vatAmount1.formatted(.currency(code: Locale.current.currency?.identifier ?? "BD")))")
                        .foregroundColor(.red)
                }

                HStack {
                    VStack(alignment: .leading) {
                        Text("Total")

                        Text(vatAmount1 > 0 ? "inc. VAT" : "")
                            .foregroundColor(Color("grayed"))

                    }
                    Spacer()
                    Text("\(totalAmount.formatted(.currency(code: Locale.current.currency?.identifier ?? "BD")))")
                        .foregroundColor(.green)
                }

                Group {
                    Section {
                        Picker("payment method", selection: $paymentM) {
                            ForEach(paymentsList, id: \.self) {
                                Text($0)
                            }
                        }
                    }
                }

//                        ShareLink("Export PDF", item: render())

            }
            .navigationTitle("Invoice Maker")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItemGroup {
                    ShareLink("Export PDF", item: render())
                        Button("Save") {

                            let income = ExpenseItem(name: customerName, type: type, amount: totalAmount - vatAmount1, date: invoiceDate, vat: vatAmount1)

                            expenses.items.insert(income, at: 0)

                            let item = HistoryData(storN: storeName, storNum: contactNumber, invNum: invoiceNumber, dat: invoiceDate, cus: customerName, cusAddr: customerAddress, cusNum: cusContactNumber, price: totalAmount)

                            historyData.item.insert(item, at: 0)

//                            showingHistoryView = true

                        }
                        //                    .sheet(isPresented: $showingHistoryView) {
                        //                        HistoryIView()
                        //                    }
                    }

                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Clear") {

                        itemsData.items.removeAll(keepingCapacity: true)

                        customerName = ""
                        customerAddress = ""
                        cusContactNumber = ""
                    }
                    .tint(.red)
                }

            }

        }

    }

    func removeItem(at offsets: IndexSet) {
        itemsData.items.remove(atOffsets: offsets)
    }

2      

Sorry @mahoozi97 :) looks a bit messy, not sure why you need all those @AppStorages. If you share full project via github maybe i can have a look at where might be the issue. But can say for sure that item is inserted just fine. I cannot play with your code as many aspects of it are missing. But if you have a look at the below code and maybe copy/paste to have a look it works just fine. Maybe the issue with passing the data to Invoice View

struct HistoryIView: View {
    @StateObject var historyData1 = DataModel()

    var body: some View {
        NavigationView {
            List {
                Section(header: Text("Invoice History \(historyData1.totalAmountView)")) {
                    ForEach(historyData1.items) { it in
                        HStack(alignment: .top) {
                            VStack(alignment: .leading) {
                                Text(it.cus)
                                Text(it.cusNum)
                                Text(it.dat.formatted(date: .abbreviated, time: .shortened))
                                    .font(.footnote)
                                    .foregroundStyle(.secondary)
                            }
                            Spacer()
                            VStack(alignment: .trailing) {
                                HStack {
                                    Text("Recipt#:")
                                        .foregroundColor(.red)

                                    Text("\(it.invNum)")
                                }

                                Text(it.price, format: .currency(code: Locale.current.currency?.identifier ?? "BD"))
                                    .foregroundColor(.green)
                            }
                        }
                    }
                    .onDelete(perform: removeItem)
                }
            }
            .navigationTitle("Invoice history")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Delete All") {
                        historyData1.items.removeAll()
                    }
                    .tint(.red)
                }

                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        let newItem = HistoryData(storN: "Test", storNum: "Test", invNum: "Test", dat: .now, cus: "Text", cusAddr: "Text", cusNum: "Text", price: 10000)
                        historyData1.items.insert(newItem, at: 0)
                    } label: {
                        Image(systemName: "plus")
                    }

                }
            }
        }
    }

    func removeItem(at offsets: IndexSet) {
        historyData1.items.remove(atOffsets: offsets)
    }
}

struct HistoryData: Identifiable, Codable {
    var id = UUID()
    let storN: String
    let storNum: String
    let invNum: String
    let dat: Date
    let cus: String
    let cusAddr: String
    let cusNum: String
    let price: Double
}

class DataModel: ObservableObject {
    @Published var items: [HistoryData] = [] {

        // FOR STORE DATA IN THE UserDefaults.
        didSet {
            let encoder = JSONEncoder()

            if let encode = try? encoder.encode(items) {
                UserDefaults.standard.set(encode, forKey: "HistoryData")

            }
        }
    }
    // FOR LOAD DATA FROM UserDefaults.
    init() {
//        if let savedItems = UserDefaults.standard.data(forKey: "HistoryData") {
//            if let decodedItems = try? JSONDecoder().decode([HistoryData].self, from: savedItems) {
//                items = decodedItems
//                return
//            }
//        }

        items = {
            var items = [HistoryData]()
            for number in 1...100 {
                let item = HistoryData(storN: "StoreN \(number)",
                                       storNum: "StoreNum \(number)",
                                       invNum: "InvNum \(number)",
                                       dat: .now,
                                       cus: "Customer \(number)",
                                       cusAddr: "Address \(number)",
                                       cusNum: "Cus \(number)",
                                       price: 100
                )
                items.append(item)
            }

            return items
        }()
    }

    var totalAmount: Double {
        items.reduce(0.0) { $0 + $1.price }
    }

    var totalAmountView: String {
        totalAmount.formatted(.currency(code: Locale.current.currency?.identifier ?? "BD"))
    }
}

2      

Hacking with Swift is sponsored by Essential Developer.

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until July 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.