Skip to content
ghiscoding edited this page Jul 20, 2021 · 42 revisions
updated doc to 3.x version
index

Description

OData Backend Service (for Pagination purposes) to get data from a backend server with the help of OData.

Note

Use it when you need to support Pagination (that is when your dataset is rather large, more than 5k rows) with a OData endpoint. If your dataset is small (less than 5k rows), then go with a regular grid with the "dataset.bind" property. SlickGrid can easily handle million of rows using a DataView object, but personally when the dataset is known to be large, I usually use a backend service (OData or GraphQL) and when it's small I go with a regular grid.

Implementation

To connect a backend service into Angular-Slickgrid, you simply need to modify your gridOptions and add a declaration of backendServiceApi and pass it the service. See below for the signature and an example further down below.

Demo

Demo Page / Demo Component

IMPORTANT NOTE

All the code below assumes that your Backend Server (probably in C#) will return the data into an items property. You could return the array directly but it is strongly discouraged to do that because that will conflict with the metrics that you will see in the code below. The best approach is to return your data into a property, like items or any property name you wish to use, on your backend server side. Your result should have this kind of structure

{ 
  items: [ /* your data */ ]
}

TypeScript Signature

backendServiceApi: {
  // Backend Service instance (could be OData or GraphQL Service)
  service: BackendService;

  // add any options you might want to provide to the backend service
  options: OdataOption | GraphqlServiceOption;

  // On init (or on page load), what action to perform?
  onInit?: (query: string) => Promise<any> | Observable<any>;

  // Before executing the query, what action to perform? For example, start a spinner
  preProcess?: () => void;

  // On Processing, we get the query back from the service, and we need to provide a Promise/Observable. For example: this.http.get(myGraphqlUrl)
  process: (query: string) => Promise<any> | Observable<any>;

  // After executing the query, what action to perform? For example, stop the spinner
  postProcess: (response: any) => void;

  // Throttle the amount of requests sent to the backend. Default to 500ms
  filterTypingDebounce?: number;
}

As you can see, you mainly need to define which service to use (GridODataService or GraphQLService) and finally add the process and postProcess callback.

Grid Definition & call of backendServiceApi

Notes
  • Pagination is optional and if not defined, it will use what is set in the Angular-Slickgrid - Global Options
  • onInit is optional and is there to initialize (pre-populate) the grid with data on first page load (typically the same call as process)
    • you could load the grid yourself outside of the gridOptions which is why it's optional
  • filterTypingDebounce is a timer (in milliseconds) that waits for user input pause before querying the backend server
    • this is meant to throttle the amount of requests sent to the backend (we don't really want to query every keystroke)
    • 750ms is the default when not provided
Code
import { Component, Injectable, OnInit } from '@angular/core';
import { Column, GridOption } from 'angular-slickgrid';
import { GridOdataService, OdataServiceApi, OdataOption } from '@slickgrid-universal/odata';

@Injectable()
export class MyComponent implements OnInit {
  columnDefinitions: Column[];
  gridOptions: GridOption;
  dataset = [];

  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    this.columnDefinitions = [
      // your column definitions
    ];

    this.gridOptions = {
      enableFiltering: true,
      enablePagination: true,
      pagination: {
        pageSizes: [10, 15, 20, 25, 30, 40, 50, 75, 100],
        pageSize: defaultPageSize,
        totalItems: 0
      },
      backendServiceApi: {
        service: new GridOdataService(),
        // define all the on Event callbacks
        options: {
          caseType: CaseType.pascalCase,
          top: defaultPageSize
        },
        // optional but typically use to show data on first page load
        // on init (or on page load), what action to perform?
        onInit: (query) => this.getCustomerApiCall(query),

        preProcess: () => this.displaySpinner(true),
        process: (query) => this.getCustomerApiCall(query),
        postProcess: (response) => {
          this.displaySpinner(false);
          this.getCustomerCallback(response);
        }
      }
    };
  }

  // Web API call
  getCustomerApiCall(odataQuery) {
    return this.http.get(`/api/getCustomers?${odataQuery}`);
  }

  getCustomerCallback(response) {
    // totalItems property needs to be filled for pagination to work correctly
    // however we need to force Angular to do a dirty check, doing a clone object will do just that
    this.gridOptions.pagination.totalItems = response.totalRecordCount;
    this.gridOptions = Object.assign({}, this.gridOptions);

    this.dataset = response.items as Customer[];
  }
}

Passing Extra Arguments to the Query

You might need to pass extra arguments to your OData query, for example passing a userId, you can do that simply by modifying the query you sent to your process callback method. For example

  // Web API call
  getCustomerApiCall(odataQuery) { with Fetch Client
    const finalQuery = `${odataQuery}$filter=(userId eq 12345)`;
    return this.http.get(`/api/getCustomers?${finalQuery}`);
  }

OData v4

By default the OData version is set to 2 because it was implemented with that version. If you wish to use version 4, then just change the version: 4, there are subtle differences.

this.gridOptions = {      
  backendServiceApi: {
    service: new GridOdataService(),
      options: {
        enableCount: true, // add the count in the OData query, which will return a property named "odata.count" (v2) or "@odata.count" (v4)
        version: 4        // defaults to 2, the query string is slightly different between OData 2 and 4
      },
      process: (query) => this.getCustomerApiCall(query),
      postProcess: (response) => {
        this.metrics = response.metrics;
        this.displaySpinner(false);
        this.getCustomerCallback(response);
      }
  } as OdataServiceApi
};

UI Sample of the OData demo

Slickgrid Server Side

Contents

Clone this wiki locally