Vue Grid Sort/Filter/Paginate do not work - dies with a spinner

I have a simple Vue.js grid and am binding the data myself. The grid is set up to be editable. Everything works perfect and I am able to edit records and (independently) update the data to the server. However, when I try to sort, filter or paginate the table, a spinner is created and processing stops - no errors are written to the console.

Here is my simplified code:

<template>

  <content-container>
    <template slot="header">
      <v-layout
        v-bind="rowMdAndUp"
        class="header elevation-1"
        :style="lightBackgroundColor">
        <v-flex>
          <span class="header-text">Sample</span>
        </v-flex>
      </v-layout>
    </template>
    <div>
      <v-card flat>
          <ejs-grid
              :ref="refgrid"
              id="refgrid"
              width="100%"
              :allowExcelExport="true"
              :allowFiltering="true"
              :allowGrouping="true"
              :allowMultiSorting="true"
              :allowPaging="true"
              :allowReordering="true"
              :allowResizing="true"
              :allowSorting="true"
              :dataSource="{ result: this.sampleData, count: this.sampleData.length }"
              :disablePageWiseAggregates="false"
              :filterSettings="filterSettings"
              :groupSettings="groupSettings"
              :pageSettings="pageSettings"
              :showColumnChooser="true"
              :showColumnMenu="false"
              :toolbar="toolbarOptions"
              :allowTextWrap="true"
              :textWrapSettings="{wrapMode: 'Header'}"
              :editSettings="editSettings"
              :dataSourceChanged="dataSourceChanged"
              :actionComplete="actionComplete"
              >
              <e-columns>
                    <e-column field='id' headerText='Id' :visible=false :showInColumnChooser='false' :isPrimaryKey='true'></e-column>
                    <e-column field='firstName' headerText='First Name'></e-column>
                    <e-column field='lastName' headerText='Last Name'></e-column>
                    <e-column field='initials' headerText='Initials'></e-column>
              </e-columns>
          </ejs-grid>
      </v-card>
    </div>
  </content-container>
</template>
<script>
import { mapGetters } from 'vuex';
import Vue from 'vue';
import { rowMdAndUp, backgroundColor } from '@/mixins';
import ContentContainer from './../../../components/ContentContainer';
import { Toolbar, ExcelExport, Group, ColumnChooser, Filter, Resize, Sort, Page, Reorder, GridPlugin, Edit } from '@syncfusion/ej2-vue-grids';


Vue.use(GridPlugin);


export default {
  provide: {
    grid: [ Toolbar, ExcelExport, Group, ColumnChooser, Filter, Resize, Sort, Page, Reorder, Edit ]
  },
  name: 'Sample',
  mixins: [rowMdAndUp, backgroundColor],
  components: { ContentContainer },
  computed: {
    ...mapGetters({
      processing: 'dataExtract/processing'
    }),
    grid() {
      return this.$refs['refgrid'];
    }
  },
  data() {
    return {
      buttonHidden: false,
      shouldDisable: false,
      filterSettings: { type: 'Excel' },
      groupSettings: { showGroupedColumn: true },
      needsColumnsAdjusted: false,
      pageSettings: { pageSizes: true, pageSize: 20 },
      toolbarOptions: ['ExcelExport', 'Add', 'Edit', 'Update', 'Cancel', 'ColumnChooser'],
      sampleData: [],
      refgrid: 'refgrid',
      editSettings: { allowEditing: true, allowAdding: true, mode: 'Dialog' }
    };
  },
  created() {
    this.getSampleData();
  },
  methods: {
    dataSourceChanged(args) {
      console.log(`Entering dataSourceChanged ${args.requestType}`);
      if (args.requestType === 'save') {
        this.editEvent = args;
        this.updateData(args.data);
      }
    },
    actionComplete(args) {
      console.log(`Entering actionComplete ${args.requestType}`);
      if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
        let dialog = args.dialog;
        dialog.header = args.requestType === 'beginEdit' ? `${args.rowData['firstName']} ${args.rowData['lastName']}` : 'New Record';
      }
      console.log(`Exiting actionComplete ${args.requestType}`);
    },
    updateData(record) { // Make a call to the server to update the record, handle the result with either endEdit or cancelEdit
      console.log('Entering updateData', record);
      this.editEvent.endEdit();
    },
    getSampleData() {
      // Get the data from the server
      this.sampleData = [
        { 'id': 1, 'firstName': 'f1', 'lastName': 'l1', 'initials': 'i1' },
        { 'id': 2, 'firstName': 'f2', 'lastName': 'l2', 'initials': 'i2' },
        { 'id': 3, 'firstName': 'f3', 'lastName': 'l3', 'initials': 'i3' }
      ];
    }
  }
};
</script>


<style lang="scss" scoped>
@import '../../../../node_modules/@syncfusion/ej2-vue-grids/styles/material.css';
</style>

Curiously, if I change the datasource to simply the data array as such:

              :dataSource="this.sampleData"

then the data state functions (sort/filter/paginate) work great, but the dataSourceChanged event is no longer triggered.

Any suggestions?

Thank you in advance

5 Replies

SK Sujith Kumar Rajkumar Syncfusion Team January 13, 2022 09:19 AM UTC

Hi Dan, 
 
Greetings from Syncfusion support. 
 
From the provided code snippet we could see that you are using custom binding approach and binding the data as an object of result and count to the Grid’s dataSource property. With custom binding, you need to handle the Grid actions from your end and update the response data to the dataSource property for updating in the Grid. We have explained the custom binding approach in detail below for your case, 
 
When the custom binding is implemented in the Grid the dataStateChange(Grid action)/dataSourceChanged(CRUD action) event will be triggered for the corresponding action along with the query details returned in the event arguments. These event arguments will return the corresponding action details from the source with which you can handle the action in your server and return back the response to the Grid. 
 
So when the filter/sort/page actions are performed in the Grid, the action details will be returned in the dataStateChange event as shown in the below image(shows filter action details), 
 
 
 
From this event you can form the filter queries in the format as required by your server and make the custom API call to your service(can be checked in the below shared documentation where we have made the API call for this approach), process the action, return back the response and bind it to the Grid dataSource as an object of ‘result’ and ‘count’. 
 
More details on custom binding can be checked in the below help documentation and online demo sample links, 
 
 
 
However if you need all the actions to be handled by the Grid itself in the client-side, then we suggest you to directly set the JSON data to the Grid’s dataSource property like you have mentioned - :dataSource="this.sampleData". And if you are using this local data binding and need to access an event on data change, then you can use the dataBound event which will be triggered on each data change. 

 
Please get back to us if you require any further assistance. 
 
Regards, 
Sujith R 



DC Dan Coppersmith January 13, 2022 03:46 PM UTC

Thank you for your response.  I tried the dataStateChange event, it never fired.   Also changing the dataSource to simply this.sampleData causes the filter/sort/pagination to work okay (even without me doing anything), but the dataSourceChanged no longer fires.

New code below.   Thanks!


<template>
  <content-container>
    <template slot="header">
      <v-layout
        v-bind="rowMdAndUp"
        class="header elevation-1"
        :style="lightBackgroundColor">
        <v-flex>
          <span class="header-text">Sample</span>
        </v-flex>
      </v-layout>
    </template>
    <div>
      <v-card flat>
          <ejs-grid
              :ref="refgrid"
              id="refgrid"
              width="100%"
              :allowExcelExport="true"
              :allowFiltering="true"
              :allowGrouping="true"
              :allowMultiSorting="true"
              :allowPaging="true"
              :allowReordering="true"
              :allowResizing="true"
              :allowSorting="true"
              :dataSource="this.sampleData"
              :dataBound="dataBound"
              :dataStateChange="dataStateChange"
              :disablePageWiseAggregates="false"
              :filterSettings="filterSettings"
              :groupSettings="groupSettings"
              :pageSettings="pageSettings"
              :showColumnChooser="true"
              :showColumnMenu="false"
              :toolbar="toolbarOptions"
              :allowTextWrap="true"
              :textWrapSettings="{wrapMode: 'Header'}"
              :editSettings="editSettings"
              :dataSourceChanged="dataSourceChanged"
              :actionComplete="actionComplete"
              >
              <e-columns>
                    <e-column field='id' headerText='Id' :visible=false :showInColumnChooser='false' :isPrimaryKey='true'></e-column>
                    <e-column field='firstName' headerText='First Name'></e-column>
                    <e-column field='lastName' headerText='Last Name'></e-column>
                    <e-column field='initials' headerText='Initials'></e-column>
              </e-columns>
          </ejs-grid>
      </v-card>
    </div>
  </content-container>
</template>
<script>
import { mapGetters } from 'vuex';
import Vue from 'vue';
import { rowMdAndUpbackgroundColor } from '@/mixins';
import ContentContainer from './../../../components/ContentContainer';
import { ToolbarExcelExportGroupColumnChooserFilterResizeSortPageReorderGridPluginEdit } from '@syncfusion/ej2-vue-grids';

Vue.use(GridPlugin);

export default {
  provide: {
    grid: [ ToolbarExcelExportGroupColumnChooserFilterResizeSortPageReorderEdit ]
  },
  name: 'Sample',
  mixins: [rowMdAndUpbackgroundColor],
  components: { ContentContainer },
  computed: {
    ...mapGetters({
      processing: 'dataExtract/processing'
    }),
    grid() {
      return this.$refs['refgrid'];
    }
  },
  data() {
    return {
      buttonHidden: false,
      shouldDisable: false,
      filterSettings: { type: 'Excel' },
      groupSettings: { showGroupedColumn: true },
      needsColumnsAdjusted: false,
      pageSettings: { pageSizes: truepageSize: 20 },
      toolbarOptions: ['ExcelExport''Add''Edit''Update''Cancel''ColumnChooser'],
      sampleData: [],
      refgrid: 'refgrid',
      editSettings: { allowEditing: trueallowAdding: truemode: 'Dialog' }
    };
  },
  created() {
    this.getSampleData();
  },
  methods: {
    dataStateChange: function(state) {
      console.log('Entering dataStateChange'state); // Never triggered!
    },
    dataBound(args) {
      console.log('Entering dataBound'args);
    },
    dataSourceChanged(args) {
      console.log(`Entering dataSourceChanged  ${args.requestType}`); // Not triggered unless use :dataSource="{ result: this.sampleData, count: this.sampleData.length }"
      if (args.requestType === 'save') {
        this.editEvent = args;
        this.updateData(args.data);
      }
    },
    actionComplete(args) {
      console.log(`Entering actionComplete  ${args.requestType}`);
      if ((args.requestType === 'beginEdit' || args.requestType === 'add')) {
        let dialog = args.dialog;
        dialog.header = args.requestType === 'beginEdit' ? `${args.rowData['firstName']} ${args.rowData['lastName']}` : 'New Record';
      }
      console.log(`Exiting actionComplete  ${args.requestType}`);
    },
    updateData(record) { // Make a call to the server to update the record, handle the result with either endEdit or cancelEdit
      console.log('Entering updateData'record);
      this.editEvent.endEdit();
    },
    getSampleData() {
      // Get the data from the server
      this.sampleData = [
        { 'id': 1'firstName': 'f1''lastName': 'l1''initials': 'i1' },
        { 'id': 2'firstName': 'f2''lastName': 'l2''initials': 'i2' },
        { 'id': 3'firstName': 'f3''lastName': 'l3''initials': 'i3' }
      ];
    }
  }
};
</script>

<style lang="scss" scoped>
@import '../../../../node_modules/@syncfusion/ej2-vue-grids/styles/material.css';
</style>



RS Rajapandiyan Settu Syncfusion Team January 14, 2022 09:23 AM UTC

Hi Dan, 
 
Thanks for your update. 
 
The dataStateChange and dataSourceChanged event will be triggered only when using custom-binding in the Grid. When binding JSON data to the Grid, those events will not be triggered. 
 
Why you want to trigger the dataStateChange and dataSourcechanged events in the Grid? Explain your requirement in detail to proceed further.  

Regards, 
Rajapandiyan S 



DC Dan Coppersmith January 14, 2022 03:40 PM UTC

My goal is to have an event triggered when the user clicks save on the dialog that opens so that I can make my calls to update the data on the server.    Using 

:dataSource="{ result: this.sampleData, count: this.sampleData.length }"

achieves this with the dataSourceChanged event.    Everything was good but then I tested the sorting and that failed.  Switching to the JSON method of binding the data fixed the sorting problem, but now I cannot find an event to fire when the SAVE is clicked.


Using

:dataSource="{ result: this.sampleData, count: this.sampleData.length }"



I was able to get rid of the spinner and change the cursor using some DOM manipulation, but that does not seem like Syncfusions intention to make the developer do that. Either way I am okay with that -- if you could send direction on how to do pagination manually, I can work with this band-aid code.

    dataStateChange: function(state) {
      console.log('Entering dataStateChange'state);
      // do the sorting/filter here
 
      document.getElementById('refgrid').style['cursor'] = '';
      [...document.getElementsByClassName('e-spinner-pane')][0].classList.remove('e-spin-show');
      [...document.getElementsByClassName('e-spinner-pane')][0].classList.add('e-spin-hide');
      // ? how to do pagenation
      return true;
    },


SK Sujith Kumar Rajkumar Syncfusion Team January 17, 2022 07:31 AM UTC

Hi Dan, 
 
As mentioned in our previous update when the data source is bound as an object of result and count, the dataStateChange and dataSourceChanged events will be triggered but for this case you would need to handle all  the actions from your end and bind the updated data to Grid’s dataSource property. 
 
So if you do not wish to handle the Grid actions from your end we suggest you to use local data binding(directly assigning the JSON data to the Grid’s dataSource property). On using this approach you can use the Grid’s actionBegin and actionComplete events which will be triggered on performing the save action and when the save action is successfully performed respectively. 
 
 
Let us know if you have any concerns. 
 
Regards, 
Sujith R  


Loader.
Up arrow icon