# useFacet

# Features

useFacet composition function can be used to fetch data related to:

  • products,
  • categories,
  • breadcrumbs.

What makes it powerful is the ability to accept multiple filters, allowing to narrow down the results to a specific category, search term, etc.

# API

useFacet contains the following properties:

  • search - function for searching and classifying records, allowing users to browse the catalog data. It accepts a single object as a parameter with following signature:

    • searchParams: AgnosticFacetSearchParams
    • limit?: number
    interface AgnosticFacetSearchParams {
      categorySlug?: string;
      rootCatSlug?: string;
      term?: string;
      page?: number;
      itemsPerPage?: number;
      sort?: string;
      filters?: Record<string, string[]>;
      metadata?: any;
      [x: string]: any;
    }
    
  • result - reactive data object containing the response from the backend.

  • loading - reactive object containing information about the loading state of search.

  • error - reactive object containing the error message if search failed for any reason.

    interface UseFacetErrors {
      search: Error;
    }
    

# Getters

Because the result property is a raw response with some additional properties, it's recommended to use facetGetters for accessing any data from it. It includes the following helper functions:

  • getAll - returns all available facets.

  • getGrouped - returns grouped facets by facet name.

  • getCategoryTree - return the tree of nested categories.

  • getSortOptions - returns available and currently selected sorting options.

  • getProducts - returns products matching current filters.

  • getPagination - returns pagination information.

  • getBreadcrumbs - returns breadcrumbs information.

    interface FacetsGetters {
      getAll: (searchData: SearchData, criteria?: string[]) => AgnosticFacet[];
      getGrouped: (searchData: SearchData, criteria?: string[]) => AgnosticGroupedFacet[];
      getCategoryTree: (searchData: SearchData) => AgnosticCategoryTree;
      getSortOptions: (searchData: SearchData) => AgnosticSort;
      getProducts: (searchData: SearchData) => ProductSearchVariant[];
      getPagination: (searchData: SearchData) => AgnosticPagination;
      getBreadcrumbs: (searchData: SearchData) => AgnosticBreadcrumb[];
    }
    
    interface AgnosticFacet {
      type: string;
      id: string;
      value: any;
      attrName?: string;
      count?: number;
      selected?: boolean;
      metadata?: any;
    }
    
    interface AgnosticGroupedFacet {
      id: string;
      label: string;
      count?: number;
      options: AgnosticFacet[];
    }
    
    interface AgnosticCategoryTree {
      label: string;
      slug?: string;
      items: AgnosticCategoryTree[];
      isCurrent: boolean;
      count?: number;
      [x: string]: unknown;
    }
    
    interface AgnosticSort {
      options: AgnosticFacet[];
      selected: string;
    }
    
    type SearchData = FacetSearchResult<FacetResultsData>
    
    interface FacetSearchResult {
      data;
      input: AgnosticFacetSearchParams;
    }
    
    interface AgnosticFacetSearchParams {
      categorySlug?: string;
      rootCatSlug?: string;
      term?: string;
      page?: number;
      itemsPerPage?: number;
      sort?: string;
      filters?: Record<string, string[]>;
      metadata?: any;
      [x: string]: any;
    }
    
    interface AgnosticPagination {
      currentPage: number;
      totalPages: number;
      totalItems: number;
      itemsPerPage: number;
      pageOptions: number[];
    }
    
    interface AgnosticBreadcrumb {
      text: string;
      link: string;
    }
    
    interface FacetResultsData {
      results: ProductProjection[];
      categories: Category[];
      facets: FacetResultValue[];
      rootCategory: Category;
      currentCategory: Category;
      total: number;
    }
    
    type ProductSearchVariant = {
      __typename?: 'ProductSearchVariant';
      id: Scalars['Int'];
      key?: Maybe<Scalars['String']>;
      sku?: Maybe<Scalars['String']>;
      prices?: Maybe<Array<ProductPriceSearch>>;
      price?: Maybe<ProductPriceSearch>;
      images: Array<ImageProductSearch>;
      assets: Array<Asset>;
      availability?: Maybe<ProductSearchVariantAvailabilityWithChannels>;
      attributesRaw: Array<RawProductSearchAttribute>;
    }
    

# Configuration

Faceting configuration can be modified in the @vsf-enterprise/commercetools/nuxt module in nuxt.config file to change available sorting options, filters, etc.

Refer to the ConfigFacetingOptions interface for more details and all available configuration options.

// nuxt.config.js
export default {
  buildModules: [
    ['@vsf-enterprise/commercetools/nuxt', {
      faceting: {
        pageOptions: [20, 50, 100],
        subcategoriesLimit: 100,
        availableFacets: [
          { facet: 'categories.id', type: 'string', option: 'subtree("*")', name: 'category', filteringStrategy: 'query' }, // Don't change the "name" of this facet
          { facet: 'variants.attributes.size', type: 'string', option: '', name: 'size', filteringStrategy: ['filter','facets'], countingProducts: true },
          { facet: 'variants.attributes.color.key', type: 'string', option: '', name: 'color', filteringStrategy: ['filter','facets'] }
        ],
        sortingOptions: [
          { id: 'latest', name: 'Latest', facet: 'createdAt', direction: 'desc' },
          { id: 'price-up', name: 'Price from low to high', facet: 'price', direction: 'asc' },
          { id: 'price-down', name: 'Price from high to low', facet: 'price', direction: 'desc' },
          { id: 'relevance', name: 'Relevance', facet: 'score', direction: 'desc' }
        ],
        filteringStrategy: 'filter'
      }
    }]
  ]
};

# Example

import { useFacet, facetGetters } from '@vsf-enterprise/commercetools';

setup(props, context) {
  const { result, search, loading } = useFacet();

  onSSR(async () => {
    await search({
      categorySlug: 'clothing',
      sort: 'latest',
      itemsPerPage: 10,
      filters: { color: ["red"], size: ["40"] },
      term: 'some search query'
    });
  });

  return {
    products: computed(() => facetGetters.getProducts(result.value)),
    categoryTree: computed(() => facetGetters.getCategoryTree(result.value)),
    breadcrumbs: computed(() => facetGetters.getBreadcrumbs(result.value)),
    sortBy: computed(() => facetGetters.getSortOptions(result.value)),
    facets: computed(() => facetGetters.getGrouped(result.value, ['color', 'size'])),
    pagination: computed(() => facetGetters.getPagination(result.value)),
    loading
  }
}