We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

Server side Custom Sorting Not Setting Sort Settings on React Grid

Hi There,


We are trying to set up Custom Sort based on Server Side call but not able to reflect  this sorting on Client side 

Our code is follows:

import { JATOToastContainer } from '@jato/ui-component-library'

import {

  ActionEventArgs,

  ColumnDirective,

  ColumnsDirective,

  Edit,

  EditSettingsModel,

  Grid,

  GridComponent,

  Inject,

  Page,

  PageSettingsModel,

  RowDataBoundEventArgs,

  RowDeselectEventArgs,

  RowSelectEventArgs,

  Selection,

  SelectionSettingsModel,

  Sort,

  SortSettingsModel,

} from '@syncfusion/ej2-react-grids'

import { vehicleGridPageSize, vehicleSelectionLimit } from 'config'

import { selectedFilters } from 'features/filters/selectedFiltersSlice'

import {

  addMpVehicle,

  mpVehicles,

  removeMpVehicle,

} from 'features/mpvehicles/mpVehiclesSlice'

import { FilterNameType } from 'models/Filters/FilterNameType'

import { ISelectedFilterOption } from 'models/Filters/FilterOption'

import { MpVehicle } from 'models/VehicleSelection/MpVehicle'

import { MpVehiclesResponse } from 'models/VehicleSelection/MpVehiclesResponse'

import React, { useEffect } from 'react'

import { useAppDispatch, useAppSelector } from 'store/hook'

import { StyledVehicleGrid } from './VehicleGrid.styles'


export interface IVehicleGridProps {

  MpVehiclesResponse: MpVehiclesResponse

  onPageChangeEvent: (ev: ActionEventArgs) => void

  onSortChangeEvent: (ev: ActionEventArgs) => void

}


export const VehicleGrid: React.FC<IVehicleGridProps> = (

  props: IVehicleGridProps

) => {

  let gridInstance: Grid | null

  const dispatch = useAppDispatch()

  const mpVehicleData: MpVehicle[] = useAppSelector(mpVehicles)


  const selectedFiltersData: ISelectedFilterOption[] = useAppSelector(

    selectedFilters

  )

  const gridData = props.MpVehiclesResponse.vehicles

  const pageSettings: PageSettingsModel = {

    pageSize: vehicleGridPageSize,

    currentPage: 1,

    totalRecordsCount: props.MpVehiclesResponse.count,

  }


  const sortingOptions: SortSettingsModel = {

    columns: [{ field: 'make', direction: 'Ascending' }],

  }


  const editOptions: EditSettingsModel = {

    allowEditing: false,

    allowAdding: false,

    allowDeleting: false,

    mode: 'Normal',

  }


  const selectionSettings: SelectionSettingsModel = {

    checkboxMode: 'Default',

    checkboxOnly: true,

    persistSelection: true,

  }


  const rowSelected = (row: RowSelectEventArgs): void => {

    if (row.isInteracted) {

      const mpVehicleData = row.data as MpVehicle

      if (row.rowIndexes?.length === vehicleSelectionLimit) {

        if (gridInstance) gridInstance.refresh()

      }

      dispatch(addMpVehicle(mpVehicleData))

    }

  }


  const rowDeselected = (row: RowDeselectEventArgs): void => {

    if (row.isInteracted) {

      if (gridInstance) {

        const selectedRows = gridInstance.getSelectedRows().length

        if (selectedRows === vehicleSelectionLimit - 1) gridInstance.refresh()

      }

      dispatch(removeMpVehicle(row.data as MpVehicle))

    }

  }


  const actionBegin = (args: ActionEventArgs): void => {

    if (args.requestType === 'paging') {

      args.cancel = true

      props.onPageChangeEvent(args)

    } else if (args.requestType === 'sorting') {

      // args.cancel = true

      props.onSortChangeEvent(args)

    }

  }


  const dataBound = (): void => {

    if (gridInstance) {

      gridInstance.pageSettings.currentPage = 1

      gridInstance.pageSettings.pageSize = vehicleGridPageSize

      if (selectedFiltersData.length > 0) {

        for (let i = 0; i < selectedFiltersData.length; i++) {

          if (selectedFiltersData[i].filterName === FilterNameType.PageSkip) {

            const skip = parseInt(selectedFiltersData[i].value)

            gridInstance.pageSettings.currentPage = skip / 20 + 1

          }

        }

      }

      gridInstance.pageSettings.totalRecordsCount =

        props.MpVehiclesResponse.count


      let rowIndex = -1

      const rowIndexes: number[] = []

      const selectedVehicleIds = mpVehicleData.map(

        (vehicle: MpVehicle) => vehicle.uniqueIdentity

      )

      gridInstance.currentViewData.forEach((row: any, index) => {

        if (selectedVehicleIds.includes(row.uniqueIdentity)) {

          rowIndex = index

          rowIndexes.push(rowIndex)

        }

      })


      gridInstance.selectRows(rowIndexes)

    }

  }


  const rowDataBound = (args: RowDataBoundEventArgs): void => {

    const vehicleData: any = args.data

    const selectedVehicleIds = mpVehicleData.map(

      (vehicle: MpVehicle) => vehicle.uniqueIdentity

    )

    if (

      selectedVehicleIds.length === vehicleSelectionLimit &&

      !selectedVehicleIds.includes(vehicleData.uniqueIdentity)

    ) {

      args.row

        ?.getElementsByClassName('e-gridchkbox')[0]

        .classList.add('disablecheckbox')

      args.row

        ?.getElementsByClassName('e-checkbox-wrapper')[0]

        .classList.add('disablecheckbox')

    }

  }


  useEffect(() => {

    if (gridInstance) {

      gridInstance.sortSettings = {

        columns: [{ field: 'make', direction: 'Ascending' }],

      }

      if (selectedFiltersData.length > 0) {

        for (let i = 0; i < selectedFiltersData.length; i++) {

          if (selectedFiltersData[i].filterName === FilterNameType.OrderBy) {

            gridInstance.sortSettings = {

              columns: [],

            }

            const sortOrderData = selectedFiltersData[i].displayValue.split('|')

            const direction =

              sortOrderData[1] === 'Ascending' ? 'Ascending' : 'Descending'

            const sortSettings: SortSettingsModel = {

              columns: [

                {

                  field: sortOrderData[0],

                  direction: direction,

                },

              ],

            }

            gridInstance.sortSettings = sortSettings

            //gridInstance.setProperties({ sortSettings: sortSettings })

          }

        }

      }

    }

  })


  return (

    <StyledVehicleGrid>

      <div className="ej-grid-header">

        <p>

          List of vehicles

          <span

            id="multiVehicleResult"

            style={{ padding: '2px' }}

            className="ng-star-inserted"

          >

            Result :{props.MpVehiclesResponse.count} vehicles

          </span>

        </p>

      </div>

      <GridComponent

        id="grid"

        ref={(g) => (gridInstance = g)}

        dataSource={gridData}

        loadingIndicator={{ indicatorType: 'Shimmer' }}

        allowPaging={true}

        allowSorting={true}

        allowSelection={true}

        allowGrouping={true}

        editSettings={editOptions}

        selectionSettings={selectionSettings}

        pageSettings={pageSettings}

        // sortSettings={sortingOptions}

        rowSelected={rowSelected}

        rowDeselected={rowDeselected}

        actionBegin={actionBegin}

        rowDataBound={rowDataBound}

        dataBound={dataBound}

      >

        <ColumnsDirective>

          <ColumnDirective type="checkbox" width="50" />

          <ColumnDirective

            field="vehicleId"

            isPrimaryKey={true}

            width="100"

            textAlign="Left"

            visible={false}

          />

          <ColumnDirective field="uniqueIdentity" width="100" visible={false} />

          <ColumnDirective

            field="make"

            headerText="Make"

            width="100"

            textAlign="Left"

          />

          <ColumnDirective

            field="model"

            headerText="Model"

            width="100"

            textAlign="Left"

          />

          <ColumnDirective

            field="versionName"

            headerText="Version"

            width="200"

            textAlign="Left"

          />

          <ColumnDirective

            field="bodyTypeDisplayValue"

            headerText="Body Style"

            width="100"

            textAlign="Left"

          />

          <ColumnDirective

            field="fuelTypeDisplayValue"

            headerText="Fuel type"

            width="100"

            textAlign="Left"

          />

          <ColumnDirective

            field="litres"

            headerText="Engine Litres"

            width="100"

            textAlign="Left"

          />

          <ColumnDirective

            field="drivenWheelsDisplayValue"

            headerText="Driven Wheels"

            width="100"

            textAlign="Left"

          />

          <ColumnDirective

            field="priceDisplayValue"

            headerText="Price"

            width="100"

          />

        </ColumnsDirective>

        <Inject services={[Sort, Page, Selection, Edit]} />

      </GridComponent>

      <JATOToastContainer

        autoClose={2000}

        closeOnClick={true}

        draggable={true}

        hideProgressBar={true}

        newestOnTop={true}

        pauseOnFocusLoss={false}

        pauseOnHover={true}

        position="top-center"

        style={{ width: 'auto' }}

      />

    </StyledVehicleGrid>

  )

}




Get this error 




3 Replies

PS Pavithra Subramaniyam Syncfusion Team March 20, 2023 11:45 AM UTC

Hi Rahul Rai,


From your shared error, we suspect that you are refreshing/updating the state while the sorting action is in progress. To validate further could you please share the below details which will be helpful for us to provide a better solution as early as possible?


  1. Share the code in the “onSortChangeEvent” method.
  2. Share the screenshot of Grid dataSource “props.MpVehiclesResponse.vehicles”.
  3. Share the Syncfusion package version.
  4. Share an issue reproducible sample which will be easier to validate at the earliest.


Also, from your code, we could see that you are performing your own Grid actions like paging, and sorting. For this, we suggest the “Custom Binding” feature which provides an option for handling the Grid actions using your own logic. So please refer to the below suggestion and check whether it meets your requirements.


For every grid action (such as FilterPage, etc.,), we have triggered the dataStateChange event and, in that event arguments we have sent the corresponding action details(like skip, take, filter field, value, sort direction, etc.,) based on that, you can perform the action in your service and return the data as a result and count object. 


Note: ‘dataStateChange’ event is not triggered at the Grid initial render. If you are using a remote service, you need to call your remote service manually with a pagination query (need to set skip value as 0 and take value based on your pageSize of pageSettings in Grid. If you are not defined pageSize in pageSettings, you need to send the default value 12 ) in load event of Grid. Please return the result like as “{result: […], count: …}” format
to Grid.


dataSourceChanged’ event is triggered when performing CRUD action in Grid. You can perform the CRUD action in your service using action details from this event and, you need to call the endEdit method to indicate the completion of the save operation.


Custom-binding: https://ej2.syncfusion.com/react/documentation/grid/data-binding/data-binding/#custom-binding

Demo: https://ej2.syncfusion.com/react/demos/#/material/grid/custom-binding


Regards,

Pavithra S




RR Rahul Rai March 24, 2023 10:09 AM UTC

Hi there,


Please find required detail below:


  1. Share the code in the “onSortChangeEvent” method.

function onSortChangeEvent(event: ActionEventArgs): void {

if (event.requestType === 'sorting') {

const customFields: string[] = Object.keys(customGridFields)

if (event.columnName) {

const columnName =

customFields.indexOf(event.columnName) !== -1

? customGridFields[event.columnName]

: event.columnName

dispatch(

addFilter({

key: uuid(),

displayValue: `${columnName}|${event.direction}`,

value: `${columnName} ${

event.direction === 'Ascending'

? MpVehicleOrderDirection.Ascending

: MpVehicleOrderDirection.Descending

}`,

filterName: FilterNameType.OrderBy,

singularFilterCategory: true,

filterParentType: FilterParentType.SpecsFilter,

})

)

}

}

}


  1. Share the screenshot of Grid dataSource “props.MpVehiclesResponse.vehicles”.

const { data: mpVehiclesResponse, isFetching } = useQuery(

[

'mpVehiclesResponse',

selectedFiltersData,

userData.accessToken,

mpReportMetaData,

],

async () => {

if (selectedFiltersData.length > 0) {

if (selectedFiltersData[i].filterName === FilterNameType.OrderBy) {

mpVehiclesSearchRequest.orderBy = []

mpVehiclesSearchRequest.orderBy.push(selectedFiltersData[i].value)

}

}

//"/(BMW:IX|JEEP:COMPASS)/" search param to be like this for make/models

if (makeFilter.length > 0 || modelFilter.length > 0) {

// Make and model search explainer:

// If only makes are selected, we need to search by all selected makes, with search queries like: /(BMW:|JEEP:)/

// If models are selected for a particular make, we can search in those selected models too with a pattern following: /(BMW:IX|JEEP:COMPASS)/ etc.

const makeModelSearchList: string[] = []


makeFilter.forEach((make) => {

let searchQuery = `${make.value}:`

if (make.subOptions !== undefined) {

// Find the models related to this make that are selected

const models = innerJoinModels(

getModelFilterOptions(make.value),

modelFilter,

make.value

)

if (models.length > 0) {

searchQuery = models.join('|')

}

}

makeModelSearchList.push(searchQuery)

})


const pipedMakeModelSearchQuery = makeModelSearchList.join('|')

mpVehiclesSearchRequest.search = `/(${pipedMakeModelSearchQuery})/`

}

}


if (

userData.accessToken.tokenValidUntil != undefined &&

userData.accessToken.tokenValidUntil < Date.now() / 1000

) {

const getAccessToken = axios.get(

`${mpbaseAPIUrlNew}/api/AccessToken/get`,

{

headers: {

ContentType: 'application/json',

},

}

)


dispatch(renewAccessToken((await getAccessToken).data))

}


if (

userData.user.settings.lastSelectedMarket?.countryCode !== undefined

) {

const { data } = await monthlyPaymentsReportService.getMpVehicleData(

mpMakeModelSearchRequest,

userData.accessToken

)

setMakeModelData(data?.vehicles)

}


const { data } = await monthlyPaymentsReportService.getMpVehicleData(

mpVehiclesSearchRequest,

userData.accessToken

)


// Convert values to display values based on API metadata mapping

data.vehicles.forEach((vehicle: MpVehicle) => {

const fuelTypeDisplayValue = findAllowedValue(

mpReportMetaData?.metadata.fuelType?.allowedValues,

vehicle.fuelType

)

const bodyTypeDisplayValue = findAllowedValue(

mpReportMetaData?.metadata.bodyType?.allowedValues,

vehicle.bodyType

)


const drivenWheelsDisplayValue = findAllowedValue(

mpReportMetaData?.metadata.drivenWheels?.allowedValues,

vehicle.drivenWheels

)


if (fuelTypeDisplayValue != undefined) {

vehicle.fuelTypeDisplayValue = fuelTypeDisplayValue.toUpperCase()

}

if (bodyTypeDisplayValue != undefined) {

vehicle.bodyTypeDisplayValue = bodyTypeDisplayValue.toUpperCase()

}

if (drivenWheelsDisplayValue != undefined) {

vehicle.drivenWheelsDisplayValue = drivenWheelsDisplayValue.toUpperCase()

}


vehicle.priceDisplayValue = formatCurrency(

vehicle.price,

vehicle.country

)

})


return data

}

)


"@syncfusion/ej2": "^20.3.56",

"@syncfusion/ej2-react-buttons": "^20.3.57",

"@syncfusion/ej2-react-calendars": "^20.3.56",

"@syncfusion/ej2-react-dropdowns": "^20.3.57",

"@syncfusion/ej2-react-grids": "^20.3.56",

"@syncfusion/ej2-react-inputs": "^20.3.57",

"@syncfusion/ej2-react-layouts": "^20.3.57",

"@syncfusion/ej2-react-navigations": "^20.3.57",

"@syncfusion/ej2-react-popups": "^20.3.57",


Thanks,

Rahul





PS Pavithra Subramaniyam Syncfusion Team April 3, 2023 12:23 PM UTC

Hi Rahul Rai,


Thanks for sharing the details.


Since you want to perform the custom sorting in Grid, we suggest canceling the default sort action inside the “actionBegin” event to overcome the reported issue. Please refer to the below code example for more information.


const actionBegin = (args: ActionEventArgs): void => {

 

  if (args.requestType === 'sorting') {

 

    args.cancel = true

 

    props.onSortChangeEvent(args)

 

  }

 

}

 



Regards,

Pavithra S


Loader.
Live Chat Icon For mobile
Up arrow icon