Problem with uploading data from Vuex storage
Tags: vue
Published: 2023-05-13 22:12:31

I have a ready-made implementation of displaying information about a Vue student in the form of a grid table. Also I need to display the same data only as a bar chart and pie chart. I decided to implement this using the library Chart.js . I have implemented the component StudentChar.vue and its display SecondView.vue. At the moment, StudentChart looks like this:

```
<template>
    <v-container>
      <v-row>
        <v-col cols="6">
          <v-card>
            <v-card-title>Круговая диаграмма распределения оценок</v-card-title>
            <v-card-text>
              <canvas ref="pieChart" width="400" height="400"></canvas>
            </v-card-text>
          </v-card>
        </v-col>
        <v-col cols="6">
          <v-card>
            <v-card-title>Столбчатая диаграмма распределения оценок по курсам</v-card-title>
            <v-card-text>
              <canvas ref="barChart" width="400" height="400"></canvas>
            </v-card-text>
          </v-card>
        </v-col>
      </v-row>
    </v-container>
  </template>
  
  <script>
  import Chart from 'chart.js';
  
  export default {
    name: 'StudentChart',
    data() {
      return {
        pieData: [],
        barData: [],
        pieChart: null,
        barChart: null,
      };
    },
    async created() {
      await this.loadData();
    },
    methods: {
      async loadData() {
        this.pieData = await this.$store.dispatch('grade/getGrades');
        this.barData = await this.$store.dispatch('grade/getCourses');
        this.createPieChart();
        this.createBarChart();
      },
      createPieChart() {
        const data = {
          labels: this.pieData.map((grade) => grade.studentName),
          datasets: [
            {
              data: this.pieData.map((grade) => grade.grade),
              backgroundColor: [
                '#FF6384',
                '#36A2EB',
                '#FFCE56',
                '#8DFF00',
                '#FF5733',
                '#C41E3D',
              ],
              hoverBackgroundColor: [
                '#FF6384',
                '#36A2EB',
                '#FFCE56',
                '#8DFF00',
                '#FF5733',
                '#C41E3D',
              ],
            },
          ],
        };
        const options = {
          responsive: true,
          maintainAspectRatio: false,
          legend: {
            display: true,
            position: 'right',
            align: 'center',
            labels: {
              boxWidth: 20,
              fontSize: 12,
            },
          },
          tooltips: {
            mode: 'index',
            intersect: false,
          },
        };
        this.pieChart = new Chart(this.$refs.pieChart, {
          type: 'pie',
          data,
          options,
        });
      },
      createBarChart() {
        const data = {
          labels: this.barData.map((course) => course.courseName),
          datasets: [
            {
              label: 'Оценки',
              backgroundColor: '#4CAF50',
              data: this.barData.map((course) => course.averageGrade),
            },
          ],
        };
        const options = {
          responsive: true,
          maintainAspectRatio: false,
          scales: {
            yAxes: [
              {
                ticks: {
                  beginAtZero: true,
                },
              },
            ],
          },
          legend: {
            display: false,
          },
          tooltips: {
            mode: 'index',
            intersect: false,
          },
        };
        this.barChart = new Chart(this.$refs.barChart, {
          type: 'bar',
          data,
          options,
        });
      },
    },
  };
  </script>
  
```
But the data is not loaded from it, but for example in the first implementation they are loaded: GrdGrid.vue:

```
<template>
    <v-data-table
        :headers="headers"
        :items="actualGrades"
        :items-per-page="15"
        item-key="code"
        class="elevation-3"
    >

        <template v-slot:top>
            <v-toolbar dense>
                <v-toolbar-title>Таблица грейдов</v-toolbar-title>
                <v-spacer></v-spacer>
                <v-btn class="primary text-lg-button"
                       @click="$store.state.grade.newGradeDialog = true"
                       x-small
                       fab
                >
                +</v-btn>
            </v-toolbar>
        </template>

        <template v-slot:item.grade="editGrade">
            <v-edit-dialog
                :return-value.sync="editGrade.item.grade"
                @save="save(editGrade)"
                @open="open(editGrade.item.grade)"
            >
                {{ editGrade.item.grade }}

                <template v-slot:input>
                    <v-text-field
                        v-model="editGrade.item.grade"
                        :rules="[rules.grade]"
                        label="Грейд"
                    ></v-text-field>
                </template>
            </v-edit-dialog>
        </template>

        <template v-slot:item.actions="item">
            <v-icon @click="deleteItem(item.item)">mdi-delete</v-icon>
        </template>

        <template v-slot:no-data v-if="!$store.state.isLoading">
            <v-btn small color="primary" @click="initData">
                Восстановить данные
            </v-btn>
        </template>
    </v-data-table>
</template>

<script>
export default {
    name: "GrdGrid",

    data() {
        return {
            headers: [
                {text: "Код", value: "code"},
                {text: "Курс", value: "courseName"},
                {text: "ФИО", value: "studentName"},
                {text: "Грейд", value: "grade"},
                {text: "Дата", value: "formatGradeDate", align: "center"},
                {text: "Удалить", value: "actions", align: "center", sortable: false}
            ],

            rules: {
                grade: val => (val && !isNaN(val) && val >= 0 && val <= 25) || "число от 0 до 25"
            },

            currentGradeValue: null
        };
    },

    methods: {
        open(value) {
            this.currentGradeValue = value;
        },
        async save(edit) {
            let isError = 1;
            if (this.rules.grade(edit.item.grade) === true) {
                try {
                    edit.item.grade = Number(edit.item.grade);
                    isError = (await this.$store.dispatch("grade/putGrade", edit.item)).resultCode;

                } catch (error) {
                    console.error(error);
                }
            }
            
            setTimeout(() => (edit.item.grade = isError ? this.currentGradeValue : Number(edit.item.grade)));
        },

        deleteItem(grade) {
            this.$store.dispatch("grade/deleteGrade", grade);
        },

        initData() {
            this.$store.dispatch("grade/initData");
        },
    },

    computed: {
        actualGrades() {
            return this.$store.state.grade.grades.filter(grade => !grade.isDelete);
        }
    },

    async mounted() {
        await this.$store.dispatch("grade/getCourses");
        await this.$store.dispatch("student/getStudents");
        await this.$store.dispatch("grade/getGrades");
    }
};
</script>

```
what could be the problem? The file grade.js from the store looks like this:

```
import api from '@/store/api'

import Grade from '../../model/Grade'
import Course from '../../model/Course'

export default {
    namespaced: true,

    state: {
        courses: new Map(),
        grades: [],
        newGradeDialog: false
    },
    
    mutations: {
        setCourses(state, courses) {
            state.courses.clear();
            courses.forEach(course => {
                state.courses.set(
                    course.code, 
                    new Course(
                        course.code,
                        course.name,
                        course.dateStart,
                        course.dateEnd
                    )
                );
            });
        },
        setGrades(state, grades) {
            state.grades = grades.map(grade => {
                return new Grade(
                    grade.code,
                    grade.courseCode,
                    grade.studentCode,
                    grade.grade,
                    grade.gradeDate,
                    grade.isDelete
                );
            });
        },

        postGrade(state, grade) {
            state.grades.push(
                new Grade(
                    grade.code,
                    grade.courseCode,
                    grade.studentCode,
                    grade.grade,
                    grade.gradeDate,
                    grade.isDelete
                )
            );
        },
        deleteGrade(state, grade) {
            const index = state.grades.indexOf(grade);
            
            grade.isDelete = 1;
            state.grades.splice(index, 1, grade);
        }
    },
    
    actions: {
        async getCourses(context) {
            context.commit('setCourses', await api.course());
        },

        async getGrades(context) {
            context.commit('setGrades', await api.grade());
        },

        async postGrade(context, grade) {
            context.commit('postGrade', await api.postGrade(grade));
        },

        async putGrade(context, grade) {
            return await api.putGrade(grade.code, grade);
        },

        async deleteGrade(context, grade) {
            if(!(await api.deleteGrade(grade.code)).resultCode) {
                context.commit('deleteGrade', grade);
            }
        },

        async initData(context) {
            context.commit('setGrades', await api.initData());
        }
    }
}
```
I've tried writing methods for loading data in different ways, but they all don't work. Also, for verification, I output the values of pie data and barbara in the methods to the console. They turned out to be undefined