Reputation: 4666
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 successfully returns the search parameters from the search-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 (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".
In other words, I take the search params from ProductListComponent
, via the UI and the model, and need to pass it in the pagination library.
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 to the library?
Upvotes: 1
Views: 502
Reputation: 13307
Looking at your question and comments, seems like you really want to pass the data to your library. In that case, I'd just use sessionStorage
to avoid any circular dependency or compiler error.
localStorage
if you want to keep the data beyond the session for better user experience.public setSearchParams(searchCriteria: string, searchText: string) {
this.searchParams = [{
searchCriteria: searchCriteria,
searchText: searchText
}];
console.log('Search params from the ProductService', this.searchParams);
sessionStorage.setItem('searchParams', JSON.stringify(this.searchParams))
}
In pagination library:
this.searchParams = JSON.parse(sessionStorage.getItem('searchParams') as string);
Upvotes: 1
Reputation: 312
why you not store your data on an subject like a behaviourSubject, and when u need u subscribe, get the data and unsubscribe
use ur service to create your behaviorSubject and store the data whenever you want, after u only have to subscribe on your service behaviorSubject
on your service do this:
yourSubject$ = new BehaviorSubject(<unknow>);
on your component that have the data:
paramsSubject$ = yourservice.yourSubject$
paramsSubject$.next("b");
And whenever you want the data do this:
paramsSubject$ = yourservice.yourSubject$
paramsSubject$.subscribe(value => {
console.log("Subscription got", value);
});
i think you can do the same thing as i answered here
Angular: how to share data from custom-component with app-component (app-root)
Upvotes: 1