UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Chart doesn't update when there is a change in the data

Forums > Swift

I'm building an app with some charts in it. The problem what i'm running into is that one of the charts doesn't re-render/refreshes when the view reappears. It only works when you go back to the iphone home screen.

This is the chart:

struct BarMarkChartComponent: View {
    var body: some View {
        ZStack {
            Rectangle()
                .fill(Color.card.background)
                .cornerRadius(UIManager.cornerRadius)
                .shadow(radius: 5)

            HStack {
                Chart(StatisticsArray.data) { data in
                    BarMark(
                        x: .value(StringConstants.status, data.status),
                        y: .value("Source", data.count)
                    )
                    .foregroundStyle(by: .value(StringConstants.status, data.status))
                    .annotation(position: .overlay, alignment: .bottom) {
                        Text("\(data.count)")
                    }
                }
                .frame(height: 300)
            }
            .padding()
        }
        .padding(.horizontal)
    }
}

This is the Array:

struct StatisticsArray: Identifiable {
    let id = UUID()
    let status: String
    var count: Int
    let color: Color
}

extension StatisticsArray {
    static var data: [StatisticsArray] = [
        .init(status: "On Radar", count: 0, color: Color.status.onRadar),
        .init(status: "Applied", count: 0, color: Color.status.applied),
        .init(status: "Off Site", count: 0, color: Color.status.offSite),
        .init(status: "On Site", count: 0, color: Color.status.onSite),
        .init(status: "Offer", count: 0, color: Color.status.offer),
        .init(status: "Challenge", count: 0, color: Color.status.challenge),
        .init(status: "Rejected", count: 0, color: Color.status.rejected)
    ]
}

This is the view where it's shown:

struct StatsView: View {

    @EnvironmentObject var vm: CoreDataViewModel

    @AppStorage("timeGoal") var currentUserTimeGoal: Date?
    @AppStorage("timeGoalDouble") var currentUserTimeGoalDouble: Double?
    @AppStorage("jobGoal") var currentUserJobGoal: Double?
    @AppStorage("contactGoal") var currentUserContactGoal: Double?
    @AppStorage("companyGoal") var currentUserCompanyGoal: Double?

    var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    Spacer()
                    CountdownComponent(referenceDate: currentUserTimeGoal ?? Date())
                    counterSection

                    BarMarkChartComponent()
                }
            }
            .navigationTitle(StringConstants.statistics)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    NavigationLink {
                        SettingsView()
                            .environmentObject(vm)
                    } label: {
                        Image(systemName: "gear")
                            .foregroundColor(.primary)
                    }
                }
            }
        }
        .onAppear {
#warning("only works first time when opening app")
            vm.statusData() // it's called everytime the view opens
        }
    }
}

This is the function I made to update the data for the chart:

    func statusData() {
        var onradarStatus: Int = 0
        var appliedStatus: Int = 0
        var offsiteStatus: Int = 0
        var onsiteStatus: Int = 0
        var offerStatus: Int = 0
        var challengeStatus: Int = 0
        var rejectedStatus: Int = 0

        for job in jobs {
            if job.status == "On Radar" {
                onradarStatus += 1
            } else if job.status == "Applied" {
                appliedStatus += 1
            } else if job.status == "Off Site Interview" {
                offsiteStatus += 1
            } else if job.status == "On Site Interview" {
                onsiteStatus += 1
            } else if job.status == "Offer" {
                offerStatus += 1
            } else if job.status == "Challenge" {
                challengeStatus += 1
            } else if job.status == "Rejected" {
                rejectedStatus += 1
            }
        }

        StatisticsArray.data[0].count = onradarStatus
        StatisticsArray.data[1].count = appliedStatus
        StatisticsArray.data[2].count = offsiteStatus
        StatisticsArray.data[3].count = onsiteStatus
        StatisticsArray.data[4].count = offerStatus
        StatisticsArray.data[5].count = challengeStatus
        StatisticsArray.data[6].count = rejectedStatus
    }

Does someone have an idea what i'm doing wrong and why?

2      

.onAppear will only be called the first time the view appears. You could also add when a change of has happened

.onChange(of: vm.jobs) { _ in
    vm.statusData()
}

PS not sure of the data (vm.jobs) but you know what changed

3      

If i replace .onAppear for the code snipped you shared. I don't see any data at all. But it works when i add it to the BarMarkChartComponent and add it to the statsView. Thanks

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.