Tuesday, 7 February 2023

How can I pass a variable from a service to a library, in this Angular app?

I have been developing an e-commerce app with Angular 14.

I am currently working on a product search feature.

export class ProductListComponent extends ComponentWithLoading implements OnInit {

    public searchCriteria: string;
    public searchText: string;
    
    constructor(
        private route: ActivatedRoute,
        private router: Router,
        private productService: ProductService
      ) {
        super();
    }
      
      
    public searchProducts(
        page?: number,
        pageSize?: number,
        searchCriteria?: string,
        searchText?: string
      ): void {
        this.showLoading();
        this.productService.setSearchParams(this.searchCriteria, this.searchText);
        this.productService
          .searchProducts(page, pageSize, searchCriteria, searchText)
          .pipe(
            take(1),
            tap((response: ApiPagination<ProductBase[]>) => {
              this.products = response.content ?? [];
              this.pageSettings = response.page;
            }),
            delay(250),
            finalize(() => this.hideLoading())
          )
          .subscribe();
      } 
}

<div class="product-search">
  <mat-form-field class="search-box">
    <input matInput placeholder="Search..." [(ngModel)]="searchText">
  </mat-form-field>

  <mat-form-field>
    <mat-select placeholder="Search by" [(ngModel)]="searchCriteria">
      <mat-option value="name">Name</mat-option>
      <mat-option value="role">Category</mat-option>
      <mat-option value="country">Country of origin</mat-option>
    </mat-select>
  </mat-form-field>

  <button mat-raised-button color="primary" (click)="searchProducts(page, pageSize, searchCriteria, searchText)">Search</button>
</div>

In the ProductService I have:

export class ProductService implements BaseService {

  public searchParams: object[];

  constructor(
    private http: HttpClient
  ) {}


  public setSearchParams(searchCriteria: string, searchText: string) {
    this.searchParams = [{
      searchCriteria: searchCriteria,
      searchText: searchText
    }];
    console.log('Search params from the ProductService', this.searchParams);
  }

  public searchProducts(
      pageNumber?: number,
      size?: number,
      searchCriteria?: string,
      searchText?: string,
      ): Observable<ApiPagination<ProductBase[]>> {
    return this.productRepo.searchProducts(pageNumber, size, searchCriteria, searchText);
  }
  
}

The setSearchParams method above sucessfully returns the search parameters from the serch-box.

I also use a pagination library to paginate the products list(s), whether they result from a search or not. Here is the library:

export class Pagination {
  public pageNumber: number;
  public size: number;
  public searchParams: object[];

  constructor(
    pageNumber?: number,
    size?: number,
    searchParams?: object[]
  ) {
    this.pageNumber = pageNumber ?? 0;
    this.size = size ?? 10;
    this.searchParams = [
      {
        searchCriteria: 'name',
        searchText: 'Laptop'
      }
    ];
  }

    public getPaginationParams(): HttpParams {
     let params = new HttpParams();

     if (this.searchParams.length) {
      this.searchParams.forEach(sp => {
        Object.entries(sp).forEach(entry => {
           params = params.append(entry[0], entry[1]);
        });
      });
    }

    params = params.append('page', this.pageNumber);
    params = params.append('size', this.size);

    return params;
  }
}

I use the library in another service:

export class ProductRepository {

    public searchParams: object[];

    constructor(private httpClient: HttpClient, private apiService: ApiService) { }

    public searchProducts(
        pageNumber?: number,
        size?: number,
        searchCriteria?: string,
        searchText?: string
      ): Observable<ApiPagination<ProductBase[]>> {
        const url = 'ProductsSearch';
        const params = new Pagination(
          pageNumber,
          size
        ).getPaginationParams();
        console.log(params);

        return this.httpClient
          .get<ApiPagination<ProductBase[]>>(this.apiService.constructUrl(url), {
              params
            }
          )
          .pipe(catchError(() => of()));
    }

}

The above class takes the params from the library and I understand the necessity. But I need to also pass the searchParams object to the library.

The goal

The goal (necessity) is to make the Pagination library take (the values of) it's search params (searchParams variable) from the ProductService service, instead of the hardcoded "name" and "Laptop".

The problem

Importing the service in the library not only seems bad software design, but it results in compilation errors.

How can I bring the search params from the ProductService service?


from How can I pass a variable from a service to a library, in this Angular app?

No comments:

Post a Comment