syncfusion / ej2-vue-ui-components

Syncfusion Vue UI component library offer more than 50+ cross-browser, responsive, and lightweight vue UI controls for building modern web applications.
https://www.syncfusion.com/vue-ui-components
Other
297 stars 64 forks source link

TypeError: Cannot read properties of undefined (reading 'pvtData') when calling refresh method after adding checkbox in Grid #112

Open mehmetdogan1180 opened 4 months ago

mehmetdogan1180 commented 4 months ago

I encountered a TypeError when trying to call the refresh method on a Syncfusion Grid that includes a checkbox column. The error message is as follows: TypeError: Cannot read properties of undefined (reading 'pvtData'). It seems that the issue might be related to the use of a custom data adaptor in the dataSource.

Steps to Reproduce:

  1. Create a Syncfusion Grid with a checkbox column.
  2. Use a custom data adaptor for the data source.
  3. Call the refresh method on the grid.

Expected Behavior: The grid should refresh without any errors, correctly displaying the checkbox column and the data.

Actual Behavior: When the refresh method is called, the following error occurs:

TypeError: Cannot read properties of undefined (reading 'pvtData')
    at __webpack_modules__../node_modules/@syncfusion/ej2-data/src/adaptors.js.UrlAdaptor.processResponse (adaptors.js:706:1)
    at __webpack_modules__../node_modules/@syncfusion/ej2-data/src/manager.js.DataManager.executeLocal (manager.js:230:1)
    at __webpack_modules__../node_modules/@syncfusion/ej2-grids/src/grid/actions/selection.js.Selection.getData (selection.js:2663:1)
    at __webpack_modules__../node_modules/@syncfusion/ej2-grids/src/grid/actions/selection.js.Selection.setCheckAllState (selection.js:3126:1)
    at __webpack_modules__../node_modules/@syncfusion/ej2-grids/src/grid/actions/selection.js.Selection.refreshHeader (selection.js:2446:1)
    at __webpack_modules__../node_modules/@syncfusion/ej2-base/src/observer.js.Observer.notify (observer.js:102:1)
    at __webpack_modules__../node_modules/@syncfusion/ej2-base/src/component.js.Component.notify (component.js:338:1)
    at __webpack_modules__../node_modules/@syncfusion/ej2-grids/src/grid/renderer/header-renderer.js.HeaderRender.refreshUI (header-renderer.js:580:1)
    at __webpack_modules__../node_modules/@syncfusion/ej2-grids/src/grid/base/grid.js.Grid.refresh (grid.js:3247:1)
    at VueComponent.refresh (grid.component.js:433:1)

Code Example: Here is the relevant code snippet that reproduces the issue:

<template>
  <div class="nz-grid-v2">
    <ejs-grid v-bind="gridProps" ref="gridInstance" v-on="gridEvents">
      <e-columns>
        <e-column type="checkbox" width="50"></e-column>
        <e-column
          v-for="(columnProps, columnIndex) in columns"
          :key="`column-${columnIndex}`"
          v-bind="columnProps"
        />
      </e-columns>
      <template v-slot:custom="{ data }">
        <component
          v-if="data.column.customType"
          :is="`${data.column.customType(data)}Template`"
          :value="
            data.column.formatter ? _formatter(data) : data[data.column.field]
          "
          :rowData="data"
          v-bind="data.column.props"
          v-on="data.column.events"
        />
        <div v-else>
          {{ _formatter(data) }}
        </div>
      </template>
    </ejs-grid>
  </div>
</template>

<script>
import {
  GridComponent,
  ColumnsDirective,
  ColumnDirective,
  Sort,
} from "@syncfusion/ej2-vue-grids";
import { DataManager, CustomDataAdaptor, Query } from "@syncfusion/ej2-data";

import { importAllComponents } from "@/utils/helper";

const templates = importAllComponents(
  require.context("./templates", true, /\.vue$/)
);

export default {
  name: "NozzleGridV2",
  components: {
    "ejs-grid": GridComponent,
    "e-columns": ColumnsDirective,
    "e-column": ColumnDirective,
    ...templates,
  },
  provide: {
    grid: [Sort],
  },
  props: {
    fields: {
      type: Object,
      default: () => ({}),
    },
    items: {
      type: [Function, Array],
      default: () => [],
    },
    remote: {
      type: Boolean,
      default: false,
    },
    sortable: {
      type: Boolean,
      default: false,
    },
    initialLoad: { type: Boolean, default: true },
    multiple: {
      type: Boolean,
      default: false,
    },
  },
  computed: {
    gridProps() {
      return {
        dataSource: new DataManager({
          adaptor: new CustomDataAdaptor({
            getData: async ({ data, onSuccess, onFailure }) => {
              console.log("data", data);
              const params = JSON.parse(data);
              try {
                const _params = {
                  page: {
                    size: this.pageSize,
                    current: 0,
                  },
                  sort: {
                    column: null,
                    direction: null,
                  },
                };
                _params.sort.column = params.sorted?.[0]?.name ?? null;
                _params.sort.direction = this._sortDirection(
                  params.sorted?.[0]?.direction
                );
                const result = await this.items(_params.page, _params.sort);
                console.log("🚀 ~ getData: ~ result:", result);
                onSuccess({
                  result: result.data,
                  count: result.total,
                });
              } catch (error) {
                console.log("error", error);
                onFailure(error);
              }
            },
          }),
        }),
        allowSorting: this.sortable,
        selectionSettings: { type: "Multiple" },
      };
    },
    columns() {
      return Object.entries(this.fields).map(([key, props]) => {
        return {
          field: key,
          headerText: props.label ?? "",
          width: props.width,
          template: props.type || props.formatter ? "custom" : undefined,
          customType:
            typeof props.type === "string" ? () => props.type : props.type,
          formatter: props.formatter,
          props: props.props ?? {},
          events: props.events ?? {},
        };
      });
    },
    gridEvents() {
      return {
        recordDoubleClick: (e) => this._onRowDoubleClick(e),
      };
    },
    grid() {
      return this.$refs.gridInstance;
    },
    gridInstance() {
      return this.grid?.$el.ej2_instances[0];
    },
  },
  data() {
    return {};
  },
  mounted() {},
  methods: {
    showLoading() {
      this.grid.showSpinner();
    },
    hideLoading() {
      this.grid.hideSpinner();
    },
    refresh() {
      console.log(this.gridInstance);
      this.grid?.refresh();
    },
    _sortDirection(direction) {
      if (!direction) return null;
      return direction === "ascending" ? "asc" : "desc";
    },
    _onRowDoubleClick(e) {
      const data = {
        data: e.rowData,
        rowIndex: e.rowIndex,
        target: e.target,
        row: e.row,
        cellIndex: e.cellIndex,
        cell: e.cell,
      };
      this.$emit("rowDoubleClick", data);
    },
    _formatter(data) {
      const payload = {
        value: data[data.column.field],
        row: data,
        index: data.index,
        columnField: data.column.field,
      };
      return data.column.formatter(payload);
    },
  },
};
</script>

<style lang="scss">
@import "@syncfusion/ej2-base/styles/material.css";
@import "@syncfusion/ej2-buttons/styles/material.css";
@import "@syncfusion/ej2-calendars/styles/material.css";
@import "@syncfusion/ej2-dropdowns/styles/material.css";
@import "@syncfusion/ej2-inputs/styles/material.css";
@import "@syncfusion/ej2-navigations/styles/material.css";
@import "@syncfusion/ej2-popups/styles/material.css";
@import "@syncfusion/ej2-splitbuttons/styles/material.css";
@import "@syncfusion/ej2-grids/styles/material.css";

.nz-grid-v2 {
  position: relative;
}
</style>

Additional Information:

SanthoshIruthayaraj commented 4 months ago

When using DataManager with CustomDataAdaptor, the DataManager expects “url” property to be set. This is the reason you are facing the current scenario. To resolve this, set a valid string to “url” property of the DataManager. Please refer to the code snippet and sample for your reference:

dataSource: new DataManager({
  url: 'url-placeholder', // provide a valid string
  adaptor: new CustomDataAdaptor({
    getData: (option) => {
       .  .  .  .  .
    },
  }),
}),

Sample: Vue Grid Custom Data Adaptor - StackBlitz