Search code examples
vue.jscomputed-propertiesag-grid-vue

Vuejs compute property doesn't get updated properly


I'm very new to Vuejs, I'm following their documentation which is very helpful. However, I find it difficult to understand how compute properties actually are triggered.

I'm using ag-grid for my project and I would like to update the total number of rows to my custom page size drop-down list.

The following is my code:

<template>
     <div id="ag-grid-demo">
      <vx-card>
       <!-- TABLE ACTION ROW -->
       <div class="flex flex-wrap justify-between items-center">
        <!-- ITEMS PER PAGE -->
        <div class="mb-4 md:mb-0 mr-4 ag-grid-table-actions-left"></div>

        <!-- TABLE ACTION COL-2: SEARCH & EXPORT AS CSV -->
        <div class="flex flex-wrap items-center justify-between ag-grid-table-actions-right">
          <vs-button class="mb-4 md:mb-0" @click="gridApi.exportDataAsCsv()">Export as CSV</vs-button>
        </div>
      </div>
      <ag-grid-vue
        ref="agGridTable"
        :gridOptions="gridOptions"
        class="ag-theme-material w-100 my-4 ag-grid-table"
        :columnDefs="columnDefs"
        :defaultColDef="defaultColDef"
        :rowModelType="rowModelType"
        @grid-ready="onGridReady"
        rowSelection="multiple"
        colResizeDefault="shift"
        :animateRows="true"
        :pagination="true"
        :paginationPageSize="paginationPageSize"
        :cacheBlockSize="cacheBlockSize"
        :enableRtl="$vs.rtl"
        :modules="modules"
      ></ag-grid-vue>
      <div class="flex flex-wrap justify-between items-center">
        <!-- CUSTOM PAGESIZE DROP-DWON -->
        <div class="mb-4 md:mb-0 mr-4 ag-grid-table-actions-left">
          <vs-dropdown vs-trigger-click class="cursor-pointer">
            <div class="p-4 border border-solid d-theme-border-grey-light rounded-full d-theme-dark-bg cursor-pointer flex items-center justify-between font-medium">
              <span class="mr-2"
              >{{ currentPage * paginationPageSize - (paginationPageSize - 1) }} - {{ recordCount - currentPage * paginationPageSize > 0 ? currentPage * paginationPageSize : recordCount }} of {{ recordCount }}</span>
              <feather-icon icon="ChevronDownIcon" svgClasses="h-4 w-4" />
            </div>
            <vs-dropdown-menu>
              <vs-dropdown-item @click="gridApi.paginationSetPageSize(10)">
                <span>10</span>
              </vs-dropdown-item>
              <vs-dropdown-item @click="gridApi.paginationSetPageSize(50)">
                <span>50</span>
              </vs-dropdown-item>
              <vs-dropdown-item @click="gridApi.paginationSetPageSize(100)">
                <span>100</span>
              </vs-dropdown-item>
              <vs-dropdown-item @click="gridApi.paginationSetPageSize(150)">
                <span>150</span>
              </vs-dropdown-item>
            </vs-dropdown-menu>
          </vs-dropdown>
        </div>

        <!-- CUSTOM TABLE PAGINATION  -->
        <div class="flex flex-wrap items-center justify-between ag-grid-table-actions-right">
          <vs-pagination :total="totalPages" :max="maxPageNumbers" v-model="currentPage" />
        </div>
      </div>
    </vx-card>
    </div>
    </template>


    <script>
import { AgGridVue } from "ag-grid-vue";
import { ServerSideRowModelModule } from "@ag-grid-enterprise/server-side-row-model";
import { MenuModule } from "@ag-grid-enterprise/menu";
import { ColumnsToolPanelModule } from "@ag-grid-enterprise/column-tool-panel";
import CompanyServices from "../../../_services/company.service";

import "@/assets/scss/vuexy/extraComponents/agGridStyleOverride.scss";

export default {
  components: {
    AgGridVue
  },
  data() {
    return {
      gridOptions: {},
      maxPageNumbers: 7,
      gridApi: null,
      defaultColDef: {
        sortable: true,
        editable: false,
        resizable: true,
        suppressMenu: false
      },
      columnDefs: [
        { headerName: "Id", field: "id", filter: false },
        {
          headerName: "Company Name",
          field: "companyName",
          filter: true,
          checkboxSelection: true,
          headerCheckboxSelectionFilteredOnly: true
        }
      ],
      rowModelType: "serverSide",
      modules: [ServerSideRowModelModule, MenuModule, ColumnsToolPanelModule],
      cacheBlockSize: 10,
    };
  },
  computed: {
    paginationPageSize() {
      if (this.gridApi) return this.gridApi.paginationGetPageSize();
      else return 10;
    },
    totalPages() {
      if (this.gridApi) return this.gridApi.paginationGetTotalPages();
      else return 0;
    },
    currentPage: {
      get() {
        if (this.gridApi) return this.gridApi.paginationGetCurrentPage() + 1;
        else return 1;
      },
      set(val) {
        this.gridApi.paginationGoToPage(val - 1);
      }
    },
   recordCount: function() {
      if (window.recordCount === undefined) return 0;
      else return window.recordCount;
   }
  },
  methods: {
    onGridReady: function(params) {
      var datasource = new ServerSideDatasource();
      params.api.setServerSideDatasource(datasource);
    }
  },
  mounted() {
    this.gridApi = this.gridOptions.api;
    this.gridColumnApi = this.gridOptions.columnApi;
  }
};    
window.ServerSideDatasource = function ServerSideDatasource(server) {
  return {
    getRows: function(params) {
      CompanyServices.list({
        startRow: params.request.startRow,
        endRow: params.request.endRow,
        SortColumn: "CompanyName",
        SortOrder: "asc"
      })
        .then(response => {
          window.recordCount = response.data.total;
          params.successCallback(response.data.rows, response.data.total);
        })
        .catch(error => {
          params.failCallback();
        });
    }
  };
};
</script>

My issue is that computed property 'recordCount' does not get updated as 'window.recordCount' being changed. 'recordCount' always shows value as zero.

Could someone please shed a light here? Thanks in advance!


Solution

  • There seems to be a couple of issues here, mainly that you are setting data and functions outside of the vue instance.

    First of all, you should not be setting any data on window, Vue has plenty of ways to handle your data and makes it all reactive for you.

    Start by moving your window.ServerSideDataSource function into the vue instance. In Vue, functions are put under "methods", so after your onGridReady function, add a , and then put:

    serverSideDatasource() {
      return {
        getRows: functions(params) {..}
      }
    }
    

    Notice that I put serverSideDatasource with a small starting s, as camelCase is widely considered best practice when naming variables and functions.

    Next, your window.recordCount should be put into Vue's data. Just add it after cacheBlockSize and set it like so:

    recordCount: 0
    

    Now that all your data and methods (functions) are within Vue, you can reach them by using "this". So replace "window." with "this." all the places you use it.

    Now, since your recordCount starts as 0, and is only changed when you call getRows, there is no need for a computed called recordCount, so delete that.

    Notice: Having both a property in data and computed called recordCount would conflict, so even if you kept it, you would have to rename the computed.

    Do tell me if this fixes it, or how far it gets you :)