thindery
thindery

Reputation: 1194

Vuex, State, & Getters

I've been stumped on getting my data to be reactive down to some chartjs charts.

I have a vuex store that when the app is mounted fires off an action to do some API cals (10 in total). Each API call is related to a department and it returns an array of all orders. That all works fine and I can see the data in vuex in the dev tools.

On my home page, I attempt to build 10 different charts. each chart has datasets related to a department's orders. The datasets are broken down to display late orders, on time, already shipped, etc.

So in my component that passes the data to the charts I use a state getter to fill out my data sets. So one of my getters is like this:

  getDepartmentLateOrders: (state) => (department) => {
    let resultArray = []
    state[department].forEach(function(order, index) {
        let now = new Date()
        let orderShipDate = new Date(order.ExpectedShipDate)
        let diff = date.getDateDiff(orderShipDate, now)
        let statusCheck = outOfProductionStatuses
        if(diff < 0 && !order.Invoiced && !statusCheck.includes(order.LastStatus)) {
            resultArray.push(order)
        }
    })
    return resultArray

Here is my store :

    const store = new Vuex.Store({
  state: {
    //These are filled from setOrdersData()
    dept1Orders: [],
    dept2Orders: [],
    dept3Orders: [],
    loaded: false,
    departmentsArray : ['dept1', 'dept2', 'dept3']
  },
  actions: {
    //This is called when the app is mounted
    loadOrders: function({ commit }) {
        let departmentSeach = this.state.departmentsArray
        departmentSeach.forEach(function(dept, index) {
            api.getDeptStatus(dept.toLowerCase()).then((response) => {
                store.commit('setOrdersData', { dept: dept, orders: response })
            }, (err) => {
                console.log(err)
            })
        })
        this.state.loaded = true
    }
  },
  mutations: {
    //For reference: https://vuex.vuejs.org/en/mutations.html
    setOrdersData: (state, payload) => {
        Vue.set(state, payload.dept+'Orders', payload.orders)
    },
  },
  getters: {
    getDepartmentLateOrders: (state) => (department) => {
        let resultArray = []
        state[department].forEach(function(order, index) {
            let now = new Date()
            let orderShipDate = new Date(order.ExpectedShipDate)
            let diff = date.getDateDiff(orderShipDate, now)
            let statusCheck = outOfProductionStatuses
            if(diff < 0 && !order.Invoiced && !statusCheck.includes(order.LastStatus)) {
                resultArray.push(order)
            }
        })

        return resultArray
    },
    getDepartmentShipTodayOrders: (state) => (department) => {
        let resultArray = []
        state[department].forEach(function(order, index) {
            let now = new Date()
            let orderShipDate = new Date(order.ExpectedShipDate)
            let diff = date.getDateDiff(orderShipDate, now)
            let statusCheck = outOfProductionStatuses

            if(diff === 0 && !order.Invoiced && !statusCheck.includes(order.LastStatus)) { //TODO: Have this not exclude the out of production orders. But maybe have it highlight so it knows?
                resultArray.push(order)
            }
        })
        return resultArray
    },
    getDepartmentOutOfProductionOrders: (state) => (department) => {
        let resultArray = []
        let statusCheck = outOfProductionStatuses
        state[department].forEach(function(order, index) {
            if(statusCheck.includes(order.LastStatus) && !order.Invoiced) {
                resultArray.push(order)
            }
        })
        return resultArray
    },
    getDepartmentShippedOrders: (state) => (department) => {
        let resultArray = []
        //let statusCheck = ['SHIPPING-3']
        state[department].forEach(function(order, index) {
            if(order.Invoiced) {
                resultArray.push(order)
            }
        })
        return resultArray
    },
    getDepartmentOnTimeOrders: (state) => (department) => {
        let resultArray = []
        //let statusCheck = ['SHIPPING-3']
        state[department].forEach(function(order, index) {
            let now = new Date()
            let orderShipDate = new Date(order.ExpectedShipDate)
            let diff = date.getDateDiff(orderShipDate, now)
            let statusCheck = outOfProductionStatuses
            if(diff > 0 && !order.Invoiced && !statusCheck.includes(order.LastStatus)) {
                resultArray.push(order)
            }
        })
        return resultArray
    },
  }
})

Here is how I get to the data in the component that needs it:

fillData () {
            let store = this.$store;
            let departmentSeach = this.departmentArray
            let that = this

            departmentSeach.forEach(function(dept, index) {
                console.log('get '+ dept)
                that[dept+'DataCollection'] = Object.assign({}, that[dept+'DataCollection'], 
                    {
                    datasets: [{
                        data: [
                            store.getters.getDepartmentShipTodayOrders(dept+'Orders').length, 
                            store.getters.getDepartmentLateOrders(dept+'Orders').length,
                            store.getters.getDepartmentOutOfProductionOrders(dept+'Orders').length,
                            store.getters.getDepartmentShippedOrders(dept+'Orders').length,
                            store.getters.getDepartmentOnTimeOrders(dept+'Orders').length
                            //12, 13, 14, 15, 16
                        ],
                        backgroundColor: that.defaultColors
                    }],
                    // These labels appear in the legend and in the tooltips when hovering different arcs
                    labels: that.defaultLables
                })
            })


            this.loadingVisible = false
            this.loaded = true

        },

The problem is that my getters are running BEFORE all my API requests are completed. I had thought that this would be fine because it would be reactive, so as data came in and set the state data, the component that is using the getter would have data bound to it because I'm referencing the state getters that are using the state data.

On my initial charts page load, the charts don't render with the data, except the very first department (probably because the API call is fast enough). If I view a page in the app and go back to the charts page all my data is in there for the other departments and it works great.

So my question... what am I doing wrong in this example that the data is not being reactive? I'm sure it's some kind of reactivity gotcha that I am overlooking.

Upvotes: 0

Views: 1641

Answers (1)

thindery
thindery

Reputation: 1194

So the main issue that this all was related to was how I instantiated my data for the charts. I set the empty department order objects in data. However, the correct way of doing it is to use computed instead because the data is derived from the store and will be reactive to the data as it comes in to my stores and the getters respond. After I did that everything worked just fine.

Upvotes: 1

Related Questions