# Sorting and filtering with Client Side Refiner

Client Side Refiner is used to lighten the load on Transformer Refiner by sorting and filtering subsets of data on the client side.

**Available from:** StreamLinkTS 7.1.16+

## Should I use Transformer Refiner or Client Side Refiner?

Client Side Refiner best complements Transformer Refiner when using it to sort and filter small containers with few subjects, particularly when the data is rapidly changing. This means fewer requests to the server, and quicker sort and filter operations.

Client Side Refiner is easier to customise quickly if you value being able to write custom sort and filter functions in TypeScript in the client.

## Enabling Client Side Refiner

Client Side Refiner is disabled by default. To enable Client Side Refiner, pass the following arguments to `StreamLinkFactory.create` when creating a `StreamLink` instance.

```typescript
var sl = StreamLink.StreamLinkFactory.create({
    // This URL is an example – use the Liberator URL according to your setup.
    liberator_urls: "ws://localhost:18080",
    clientside_refiner_enable: true
})
```

## Configuring Client Side Refiner

Configure Client Side Refiner by setting the following keys in the configuration object you pass to `StreamLinkFactory.create`. A full list of configuration-object keys can be found in the documentation for [StreamLinkFactory](https://docs.caplin.com/developer/api/streamlinkts/latest/classes/StreamLinkFactory.html).

* **clientside_refiner_enable**

  **Default:** `false` | **Type:** `boolean`

  When set to true, enables the Client Side Refiner and allows other arguments to take effect.
* **clientside_refiner_fn_use_for**

  **Default:** `undefined` | **Type:** `function`

  If `clientside_refiner_enable` is true, this function determines if individual container subscriptions should be refined on the client or server.

  Returning `true` from this function will enable Client Side Refiner for the container subject matching the `subject` parameter.

  **Example:**

  **Using Client Side Refiner for container subscriptions under EXAMPLES/PRICING**

  ```typescript
  StreamLinkFactory.create({
      // ...
      clientside_refiner_fn_use_for: (subject: String, parameters: SubscriptionParameters): boolean => {
          return subject.includes("EXAMPLES/PRICING");
      }
  })
  ```
* **clientside_refiner_custom_sorts**

  **Default:** `undefined` | **Type:** `object`

  `clientside_refiner_custom_sorts` takes an object consisting of key-value pairs mapping custom sort names to their sort functions.

  See [Refiner subject syntax](../transformer/transformer-refiner-filtering-and-sorting-rules.md#sort-expressions) for how to construct subject sort parameters.

  **Example:**

  **Sort items containing the text "Inc."**

  ```typescript
  const daysOfWeek = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];

  function sortByDay(a: any, b: any): number  {
      const dayA = daysOfWeek.indexOf(a);
      const dayB = daysOfWeek.indexOf(b);

      if (dayA < dayB) {
          return -1;
      } else if (dayA > dayB) {
          return 1;
      } else {
          return 0;
      }
  }

  var streamlink = StreamLinkFactory.create({
      // ...
      clientside_refiner_custom_sorts: {
          sort_by_day: sortByDay
      }
  });
  ```
* **clientside_refiner_custom_filters**

  **Default:** `undefined` | **Type:** `object`

  `clientside_refiner_custom_filters` takes an object consisting of key-value pairs mapping custom filter names to their filter functions.

  The filter functions can be one of two types:

  1. A comparator function with the signature `(fieldValue: string, filterCriterion: string): number`, similar to the functions provided to `clientside_refiner_custom_sorts`.

     This type should be used when the filter expression is of the form `where:customFilterName:<fieldname>:<operator>:<value>`.
  2. A function with the signature `(fieldProvider: IFieldProvider): boolean`, where `fieldProvider` contains the method `getField(fieldName: string): any`, which is used to get a field from the record being filtered.

     This type should be used when the filter expression is of the form `where:x`.

  See [Refiner subject syntax](../transformer/transformer-refiner-filtering-and-sorting-rules.md#filter-expressions) for how to construct subject filter parameters.

  **Examples:**

  **Custom filter by grade (type A)**

  ```typescript
  const grades = ['A', 'A+', 'AA-', 'AA', 'AA+', 'AAA'];

  function gradeFilter(fieldValue: string, filterCriterion: string): number {

    const fieldValueRank = grades.indexOf(fieldValue);
    const filterCriterionRank = grades.indexOf(filterCriterion);

    if (fieldValueRank === filterCriterionRank) {
      return 0;
    } else if (fieldValueRank < filterCriterionRank) {
      return -1;
    } else {
      return 1;
    }
  }

  var streamLink = StreamLinkFactory.create({
      // ...
      clientside_refiner_custom_filters: {
          grade_filter: gradeFilter
      }
  });
  ```

  **Custom filter by a combination of fields (type B)**

  ```typescript
  function spreadTargetFilter(fieldProvider: { getField: (name: string) => any }): boolean {
      const bestAsk = Number(fieldProvider.getField("BestAsk"));
      const bestBid = Number(fieldProvider.getField("BestBid"));
      const spreadTarget = Number(fieldProvider.getField("SpreadTarget"));

      return bestAsk - bestBid >= spreadTarget;
  }

  var streamLink = StreamLinkFactory.create({
      // ...
      clientside_refiner_custom_filters: {
          spread_target_filter: spreadTargetFilter
      }
  });
  ```
