Search code examples
typescriptvue.jsvuexquasar

Data not syncing between Vuex Store and Vue Component


I'm having trouble within a component of a Quasar project I am currently doing. I'm currently using a Q-table which pulls information from a data field. This data field is given the value of the data field in the Vuex store which should sync automatically, however this does not happen so. If I go out of the component and go back into it, then the data field changes but whenever I am on the component it seems like the component does not reload to sync the data. Any help would be appreciated The Vuex Store code is below:

import { Module, VuexModule, getModule, Mutation, Action } from 'vuex-module-decorators'
import { websocket } from 'src/boot/socket.io-client'
import store from 'src/store'
import { AcademicProgramData, AcademicProgramPagination, AcademicProgramQualification, AcademicProgramStatus } from './types'
export { AcademicProgramData, AcademicProgramPagination, AcademicProgramStatus, AcademicProgramQualification } from './types'

export interface AcademicProgramState {
  data: AcademicProgramData [],
  filter: string,
  statuses: AcademicProgramStatus [],
  qualifications: AcademicProgramQualification [],
  pagination: AcademicProgramPagination
}

@Module({
  name: 'academicProgram',
  namespaced: true,
  dynamic: true,
  store
})

class AcademicProgram extends VuexModule implements AcademicProgramState {
  public data: AcademicProgramData []= []

  public filter: string = ''
  public statuses: AcademicProgramStatus [] = []
  public qualifications: AcademicProgramQualification [] = []
  public pagination: AcademicProgramPagination = {
    descending: true,
    rowsNumber: 10,
    rowsPerPage: 10,
    page: 1,
    sortBy: 'name'
  }
  get getData() {
    return this.data
  }

  @Mutation 
  public SET_PAGINATION(pagination: AcademicProgramPagination) {
    this.pagination = pagination
  }

  @Mutation
  public SET_FILTER(filter: string) {
    this.filter=filter
  }

  @Mutation
  public SET_DATA (data: AcademicProgramData []) {
    this.data = data
  }

  @Mutation 
  public SET_STATUSES (statuses: AcademicProgramStatus []) {
    this.statuses=statuses
  }

  @Mutation 
  public SET_QUALIFICATIONS (qualifications: AcademicProgramQualification []) {
    this.qualifications=qualifications
  }

  @Mutation
  public SET_PAGINATION_VARS (total: number, listtotal: number)
  {
    this.pagination.rowsNumber=total
  }

  @Action
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  public async fetchData() {
    let dir: string=''
    if(this.pagination.descending===true) {
      dir='DESC'
    }
    else {
      dir='ASC'
    } 
    await websocket.emit('query', `{
      academicPrograms(
        page: {
          skip: 0
          first: ${this.pagination.rowsPerPage}
        }
        filter: {
          ilike: {
            name: "${this.filter}"
          }
        }
        order: {
          by: ${this.pagination.sortBy}
          dir: ${dir}
        }
      ) {
        pagination {
          total
          listTotal
        }
        list {
          id
          name
          code
          type {
            id
            name
          }
          status {
            id
            name
          }
        }
      }
    }`, (response: { errors: any; data: { academicPrograms: { list: AcademicProgramData[]; pagination: { total: number; listTotal: number; } } } }) => {
      console.log(response.data.academicPrograms.list)
      this.SET_DATA(response.data.academicPrograms.list)
      this.SET_PAGINATION_VARS(response.data.academicPrograms.pagination.total, response.data.academicPrograms.pagination.listTotal)
    })
  }

  @Action
  public async getQualifications() {
    await websocket.emit('query', `{
      academicProgramTypes
      {
        pagination {
          total
          listTotal
        }
        list {
          id
          name
        }
      }
    }`, (response: { errors: any; data: { academicProgramTypes: { list: AcademicProgramData []; pagination: { total: number } } } }) => {
      this.SET_QUALIFICATIONS(response.data.academicProgramTypes.list)
    })
  }

  @Action
  public async getStatuses() {
    await websocket.emit('query', `{
      academicProgramStatuses
      {
        pagination {
          total
          listTotal
        }
        list {
          id
          name
        }
      }
    }`, (response: { errors: any; data: { academicProgramStatuses: { list: AcademicProgramData []; pagination: { total: number } } } }) => {
      this.SET_STATUSES(response.data.academicProgramStatuses.list)
    })
  }

  @Action
  public async addAcademicProgram(input: AcademicProgramData) {
    await websocket.emit('query', `mutation {
      createAcademicProgram (
        academicProgram: {
          code: "${input.code}"
          name: "${input.name}"
          typeId: "${input.type.id}"
          statusId: "${input.status.id}"
        }
      ) {
        id
        ok
        message
      }
  }`, (response: {errors: any; data: {id: any; ok: boolean; message: String} } ) => {
      console.log(response)
    })
  }

  @Action
  public async editAcademicProgram(input: AcademicProgramData) {
    await websocket.emit('query', `mutation {
      updateAcademicProgram (
        academicProgram: {
          id: "${input.id}"
          code: "${input.code}"
          name: "${input.name}"
          typeId: "${input.type.id}"
          statusId: "${input.status.id}"
        }
      ) {
        id
        ok
        message
      }
    }`, (response: {errors: any; data: {id: any; ok: boolean; message: String}}) => {
      console.log(response)
    })
  }

  @Action
  public async deleteAcademicProgram(input: AcademicProgramData) {
    await websocket.emit('query', `mutation {
      deleteAcademicProgram (
        academicProgramId: "${input.id}"
      ) {
        id
        ok
        message
      }
    }`, (response: {errors: any; data: {id: any; ok: boolean; message: String } }) => {
      console.log(response)
    })
  }
}

export const AcademicProgramModule = getModule(AcademicProgram)

My Component code is as follows:

<template>
  <div>
    <q-toolbar
      class="bg-grey-1 text-subtitle1 text-blue-grey-8 shadow-2 rounded-borders"
    >
      <q-breadcrumbs class="text-grey" active-color="primary">
        <template v-slot:separator>
          <q-icon size="24px" name="arrow_forward" color="primary" />
        </template>

        <q-breadcrumbs-el
          label="Settings"
          icon="settings"
          class="hover cursor-pointer"
          @click="$router.push('/system')"
        />
        <q-breadcrumbs-el
          label="Academic Program"
          icon="description"
        />
      </q-breadcrumbs>
    </q-toolbar>
    <q-table class="q-mt-sm" 
      :columns="columns" 
      :data.sync="data"
      :pagination.sync="pagination"
      row-key="id"
      selection="single"
      :selected.sync="selected"
      @request="changePagination"
    >
      <template slot="top">

        <q-input
          v-model="filter"
          clearable
          placeholder="Search by Academic Program"
          type="text"
          class="col-3"
          @keypress.enter.native="search"
        />
        <q-btn
          class="q-pl-sm q-pr-sm"
          color="primary"
          flat
          @click="$refs.addAcademicProgram.toggle()"
        >
          <q-icon name="fas fa-plus" />
          <q-tooltip
            anchor="top middle"
            self="bottom middle"
            :offset="[10, 10]"
          >
            <strong>Add new Academic Program</strong>
          </q-tooltip>
        </q-btn>
        <q-btn
          class="q-pl-sm"
          color="primary"
          :disable="!selected.length"
          flat
          @click="$refs.editAcademicProgram.toggle()"
        >
          <q-icon name="fas fa-pencil-alt" />
          <q-tooltip
            anchor="top middle"
            self="bottom middle"
            :offset="[10, 10]"
          >
            <strong>Edit Academic Program</strong>
            <br />Select record first
          </q-tooltip>
        </q-btn>
        <div class="col" />
        <q-btn
          color="negative"
          :disable="!selected.length"
          flat
          round
          @click="$refs.deleteAcademicProgram.toggle()"
        >
          <q-icon name="fas fa-trash-alt" />
          <q-tooltip
            anchor="top middle"
            self="bottom middle"
            :offset="[10, 10]"
          >
            <strong>Delete Academic Program</strong>
            <br />Select record first
          </q-tooltip>
        </q-btn>
      </template>
    </q-table>
    <addAcademicProgram ref="addAcademicProgram"></addAcademicProgram>
    <editAcademicProgram
      :data="selected"
      ref="editAcademicProgram"
    ></editAcademicProgram>
    <deleteAcademicProgram :data="selected" ref="deleteAcademicProgram"></deleteAcademicProgram>
  </div>
</template>

<script lang="ts">
import { Vue, Component, Watch } from 'vue-property-decorator'
import { AcademicProgramModule, AcademicProgramQualification, AcademicProgramStatus, AcademicProgramData, AcademicProgramPagination } from 'src/store/academicProgram'
import AddAcademicProgram from './AddAcademicPrograms.vue'
import EditAcademicProgram from './EditAcademicPrograms.vue'
import DeleteAcademicProgram from './DeleteAcademicPrograms.vue'

@Component({
  components: {
    addAcademicProgram: AddAcademicProgram,
    editAcademicProgram: EditAcademicProgram,
    deleteAcademicProgram: DeleteAcademicProgram
  }
})
export default class ManageAcademicProgram extends Vue {
  private filter: string = AcademicProgramModule.filter
  private selected: AcademicProgramData [] = []
  private pagination: AcademicProgramPagination = AcademicProgramModule.pagination

  private columns = [
    {
      name: 'code',
      label: 'Code',
      align: 'center',
      required: true,
      field: 'code',
      sortable: true
    },
    {
      name: 'name',
      label: 'Name',
      align: 'center',
      required: true,
      field: 'name',
      sortable: true
    },

  ]

  private getstatuses: AcademicProgramStatus [] = AcademicProgramModule.statuses

  private qualifications: AcademicProgramQualification [] = AcademicProgramModule.qualifications

  private data: AcademicProgramData [] = AcademicProgramModule.data

  changePagination() {
    AcademicProgramModule.SET_PAGINATION(this.pagination)
    AcademicProgramModule.fetchData()
  }

  search() {
    console.log("Searched")
    if(this.filter===null)
    {
      this.filter=''
    }

    AcademicProgramModule.SET_FILTER(this.filter)
    AcademicProgramModule.fetchData()

    console.log('component data... ',this.data)
  }

  beforeMount() {
    AcademicProgramModule.fetchData()
    AcademicProgramModule.getStatuses()
    AcademicProgramModule.getQualifications()
  }
}
</script>

Solution

  • to me it looks that you assign data with reference1 in your component, and expect it to change its reference when you change any other variable in your vuex store. use the store reference to aquire your data array

    AcademicProgramModule.data = [1,2,3]
    ...
    private data: AcademicProgramData [] = AcademicProgramModule.data
    
    ...
    AcademicProgramModule.data = [4,5,6]
    ...
    console.log(data) // [1,2,3]
    
    //better
    
    get data(){
      return AcademicProgramModule.data
    }