SPARTACUS 自定义 SearchboxComponent 服务

SPARTACUS customization of SearchboxComponent service

问题:我正在处理自定义搜索框配置,因为我们的搜索 API 端点需要 3 个额外参数。应使用动态参数调用端点。

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

到目前为止我收到了以下说明:

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.

基于以上我得出了以下结论:

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')
        });
}

但是我仍然无法订阅 SearchResults 可观察对象。你能帮我解决这个问题吗?

感谢提问。我想我最初在 slack 上回答你时忽略了一些事情。

首先,SearchBoxComponentService.search 不仅获取搜索配置并将其传递给 SearchboxService。它只从配置中获取细节。因此,我建议改写 SearchboxService,即:

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

使用此设置,您的配置将最终处于操作状态,因此可在 OccProductSearchAdapter 上使用。适配器将使用 searchConfig 创建端点。

您现在可以通过向 Spartacus 提供配置来使用动态参数配置您的搜索端点:

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

但是,这将不会允许动态路径属性。我会和团队谈谈,看看我们是否可以允许这样做。您也许可以更改端点以改为使用查询参数,这样您就可以开始了。

要使用路径参数,您需要评估这些方法:

  • 自定义 OccProductSearchAdapter 并实施 getSearchEndpoint。您可以利用 searchConfig 参数并输入路径参数。
  • 引入一个angular拦截器。这不是很干净,因为所有 http 请求都将通过此拦截器。
  1. 作为 @tobi-or-not-tobi ,最简单的方法是在 SearchConfig.

    中传递您的自定义动态参数。
  2. 目前,OccProductSearchAdapter.search() 方法默认将 SearchConfig 对象的每个 属性 放入端点的查询参数中。因此,即使您保留默认的端点形状,您也会开箱即用您的自定义参数作为查询参数附加:products/search?fields=...&query=...&pageSize=...&soldTo=...shipTo=...&businessCategory=...

    这是因为 OccProductSearchAdapter.getSearchEndpoint() 在通用 url 构建器 OccEndpointsService 中调用,同时将 SearchConfig 作为第三个参数传递(仅用于构建查询参数):

    protected getSearchEndpoint(
      query: string,
      searchConfig: SearchConfig
    ): string {
      return this.occEndpoints.getUrl(
        'productSearch',  // endpoint name
        {},               // url params for placeholders ${...}
        {                 // query params to append:
          query,
          ...searchConfig,
        }
      );
    }
    
  3. 为了实现您的目标(动态参数是 url 参数的一部分),您需要:

    i) 在端点配置中添加 ${} 占位符:

    provideConfig({
      backend: {
        occ: {
          endpoints: {
            productSearch:
              'products/search/${shipTo}/${soldTo}/${businessCategory}?fields=FULL`'
          }
        }
      }
    })
    

    ii) 自定义方法 OccProductSearchAdapter.getSearchEndpoint()SearchConfig 对象中解压自定义参数并将它们作为第二个参数传递给通用 url 建设者。例如,在您的 app.module 中,提供:

     @Injectable()
     export class CustomOccProductSearchAdapter extends OccProductSearchAdapter {
       protected getSearchEndpoint(
         query: string,
         searchConfig: SearchConfig
       ): string {
         // unpack custom params:
         const {
           shipTo,
           soldTo,
           businessCategory,
           ...restSearchConfig
         } = searchConfig as any;
    
         return this.occEndpoints.getUrl(
           'productSearch',      // endpoint name
           {                     // url params for placeholders ${...}:
             shipTo,
             soldTo,
             businessCategory,
           },
           {                    // query params to append:
             query,
             ...restSearchConfig,
           }
         );
       }
     }
    
     // AppModule:
     @NgModule({
       /* ... */
       providers: [
         {
           provide: ProductSearchAdapter,
           useClass: CustomOccProductSearchAdapter,
         },
       ]
    

注意:@Nagaprasad Vendra mentioned in 表示CustomSearchboxServicesearch()方法没有被调用。澄清一下:此服务仅处理辅助搜索结果(搜索框中的建议)。 ProductListingComponent 使用不同的外观来获取搜索结果 - ProductSearchService。所以你也需要自定义那个。