Search code examples
spartacus-storefront

SPARTACUS customization of SearchboxComponent service


Problem: I am working on a custom search box configuration, as our search API endpoint requires 3 additional parameters. The endpoint should be called with dynamic parameters.

https://localhost:9002/occ/v2/{baseSiteId}/products/customsearch/param1/param2/param3?query=xyz&pageSize=5&lang=en&curr=USD&currentPage=1

I've received the following instructions so far:

The searchbox component is delegating the actual search to the SearchBoxComponentService. This service is using the SearchboxService which is a facade around the central store and lower level connectors/adapters. The search box configuration is passed into the facade/store, which you could use to extend the search query that is ending up at the backend.

You should start providing a custom version of SearchBoxComponentService, and override the search() method. If the additional search parameters would match the endpoint configuration query parameters, I believe you're good to go, but honestly i'm doing this from top of head so I might miss something.

Basis on the above i've came up with the following:

search(query: string, config: SearchBoxConfig): Observable<SearchResults> {
    if (!query || query === '') {
        this.clearResults();
        return;
    }

    if (
        config.minCharactersBeforeRequest &&
        query.length < config.minCharactersBeforeRequest
    ) {
        return;
    }

    if (config.displayProducts) {
        this.ProductSearch(query, {
        pageSize: config.maxProducts,
        }).subscribe(data => {
        return data;
        }, error => {
        });
    }

    if (config.displaySuggestions) {
        this.searchService.searchSuggestions(query, {
        pageSize: config.maxSuggestions,
        });
    }
}

    
// tslint:disable-next-line: typedef
ProductSearch(query: string, searchConfig?: SearchConfig): Observable<SearchResults> {
    const pageSize = searchConfig.pageSize ? searchConfig.pageSize : 5;
    const currentPage = searchConfig.currentPage ? searchConfig.currentPage : 1;
    const fetchUrl = `${this.occEndpointsService.getBaseEndpoint()}/products/markethubsearch/${this.soldTo}/${this.shipTo}/${this.businessCategory}?query=${query}&pageSize=${pageSize}&lang=en&curr=USD&currentPage=${currentPage}`;
    
        return this.http.get<SearchResults>(fetchUrl, {
        params: new HttpParams().set('fields', 'FULL')
        });
}

I am however still unable to subscribe to the SearchResults observable. Can you please help me with this?


Solution

  • Thanks for the question. I guess I've overlooked a few things when I initially answered you on slack.

    To begin with, the SearchBoxComponentService.search doesn't just take the search config and pass it down to the SearchboxService. It does only takes specifics from the config. Therefor, I'd recommend to override the SearchboxService instead, i.e.:

    @Injectable({
      providedIn: 'root',
    })
    export class CustomSearchboxService extends SearchboxService {
      search(query: string, config?: SearchConfig): void {
        super.search(query, { ...config, foo: 'bar' } as SearchConfig);
      }
    }
    

    With this setup, your config will end up in the action state and therefor available at the OccProductSearchAdapter. The adapter will use the searchConfig to create the endpoint.

    You can now configure your search endpoint, using dynamic parameters, by providing a configuration to Spartacus:

    provideConfig({
      backend: {
        occ: {
          endpoints: {
            productSearch:
              'products/search?fields=products(code)&foo=${foo}'
          }
        }
      }
    })
    

    However, this will not allow for dynamic path properties. I'll talk to the team to see if we can allow for this. You might be able to change your endpoints to work with query parameters instead, and you'd be good to go.

    To work with path parameters you evaluate these approaches:

    • customize the OccProductSearchAdapter and implement the getSearchEndpoint. You can leverage the searchConfig argument and feed in the path parameters.
    • introduce an angular interceptor. This isn't so clean, as all http requests will go through this interceptor.