# useFilterCollection

**Category:** Features/Filter/Hooks

## Design

### Overview

React hook that connects a filter to a collection state.

This allows a visitor to select items from a server and filter the filter collection by those items.

### Examples

### Basic

```tsx
import { Avatar } from '@wix/design-system';
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import {
  CollectionToolbarFilters,
  Filter,
  idNameArrayFilter,
  Table,
  MultiSelectCheckboxFilter,
  useTableCollection,
  useFilterCollection,
  OffsetQuery,
} from '@wix/patterns';
import { contacts } from '@wix/crm';

interface Contact {
  id: string;
  name: string;
}

type ContactsFilters = {
  contacts: Filter<Contact[]>;
};

function ContactsFilterCollection() {

  const state = useTableCollection<contacts.Contact, ContactsFilters>({
    queryName: 'contacts-ContactsFilterCollection',
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchData: (query: OffsetQuery<ContactsFilters>) => {
      const { limit, offset, search, filters } = query;

      let queryBuilder = contacts.queryContacts().limit(limit).skip(offset);

      if (search) {
        queryBuilder = queryBuilder.startsWith('info.name.first', search);
      }

      if (filters.contacts) {
        queryBuilder = queryBuilder.in(
          '_id',
          filters.contacts.map(({ id }) => id),
        );
      }

      return queryBuilder.find().then(({ items = [], totalCount: total }) => ({
        items,
        total,
      }));
    },
    fetchErrorMessage: () => 'Error fetching contacts',
    filters: {
      contacts: idNameArrayFilter(),
    },
  });

  const collection = state.collection;

  const contactsCollection = useFilterCollection<Contact>(
    collection.filters.contacts,
    {
      queryName: 'contacts',
      paginationMode: 'offset',
      fetchData: (query: OffsetQuery) => {
        const { limit, offset, search } = query;

        let queryBuilder = contacts.queryContacts().limit(limit).skip(offset);

        if (search) {
          queryBuilder = queryBuilder.startsWith('info.name.first', search);
        }

        return queryBuilder
          .find()
          .then(({ items = [], totalCount: total }) => ({
            items: items.map((item) => ({
              id: item._id!,
              name: `${item.info?.name?.first} ${item.info?.name?.last}`,
            })),
            total,
          }));
      },
      limit: 50,
      filters: {},
    },
  );

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Table
          state={state}
          columns={[
            {
              title: '',
              width: '48px',
              render: (contact) => (
                <Avatar
                  name={`${contact.info?.name?.first} ${contact.info?.name?.last}`}
                  imgProps={{ src: contact.info?.picture?.image }}
                />
              ),
            },
            {
              title: 'Name',
              render: (contact) =>
                `${contact.info?.name?.first} ${contact.info?.name?.last}`,
            },
          ]}
          filters={
            <CollectionToolbarFilters inline={1}>
              <MultiSelectCheckboxFilter
                toolbarItemProps={{
                  label: 'Filter by',
                }}
                filter={collection.filters.contacts}
                collection={contactsCollection}
              />
            </CollectionToolbarFilters>
          }
        />
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

## API

### Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `fetchTotal` | `FetchTotalFn` | No | - | A function that fetches the total number of items in the collection.<br> <br> Supported parameters: <br> - `query`: [object] [ComputedQuery](./com?path=/story/common-models--computedquery) of type `CursorQuery`. <br> <br> Must return a number Promise. |
| `limit` | `number` | No | - | Maximum number of items fetched per page. |
| `disableAutoSelectAllCount` | `boolean` | No | - | Whether to disable "Select All" server simulation for bulk selection. |
| `useNewSelectAllLogic` | `boolean` | No | - | Whether to enable new "Select All" logic. <br> <br> If `true`: <br> - Unchecking items after checking "Select All" does not fallback to specific selection logic and values. This means in `<bulkActionToolbar />` and `<MultiBulkActionToolbar />`, "Total Selected" will show `total - unchecked items` and `isSelectAll` will be true. <br> - You will receive a list of unchecked IDs. |
| `queryName` | `string` | Yes | - | Unique value for each API endpoint consumed in `fetchData`. |
| `fqdn` | `string` | No | - | Entity fqdn. |
| `toExtendedFields` | `((item: T) => ExtendedFields \| null)` | No | - | The `ExtendedFields` object used to render custom field values Optional in case your data complies to the type `{ extendedFields: ExtendedFields }` |
| `persistQueryToUrl` | `boolean` | No | `false` | Persist the selected filters, search & sort in the query parameters of the URL.<br/> For improved readability, sort & columns are formatted in CSV-like formatting, i.e "?sort=name+desc,price+asc". Do not use commas and/or spaces for your columns IDs.<br> Note: The filters from the selected view will be persist, but the actual view will not be selected |
| `refreshOnColumnsChange` | `boolean` | No | `false` | Whether the collection refreshes when different columns are selected. <br> <br> Selected columns are passed in `fetchData(query.columns)`. |
| `selectionConsistencyMode` | `"clear" \| "preserve"` | No | `preserve` | Preserve or clear selection after applying a new search or filter. |
| `events` | `CollectionEvents<F>` | No | - | Optional callbacks for various events of the collection state lifecycle - `onInitialPageFetched` - when the first page of items is ready - `onSearch` - when fetching new items as a result new search - `onSearchResults` - when the result of a search is ready - `onNewPageStart` - when starting to load the next page of items - `onNewPageAdded` - when the result of the next page is ready - `onError` - When `fetchData` throws an error. Return `true` from this function if the error was reported and shouldn't be reported again internally. |

