I am using angular 6 here with angular material and I'm trying to build a search component that uses graphQL with Apollo.
well, the component works, but I would like to address these issues:
My product service that interacts with the graphQL server:
import { Injectable } from '@angular/core';
import {Apollo} from 'apollo-angular';
import gql from 'graphql-tag';
@Injectable({
providedIn: 'root'
})
export class ProductService {
constructor(private apollo: Apollo) { }
searchForProduct(productName: string) {
return this.apollo.watchQuery<any>({
query: gql`{products_by_p_name_search(lang_id:1,query:"${productName}")
{category_id,price,category_name,id,name,desc,quantity,year_manufacture,image_file}}`
});
}
}
my search component html with the mat-autocomplete
component:
<form class="example-form">
<mat-form-field class="example-full-width">
<input matInput placeholder="חפש מוצר" aria-label="חפש מוצר" [matAutocomplete]="auto" [formControl]="productCtrl">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let product of products" [value]="product.name">
<img class="example-option-img" aria-hidden src="../../assets/products/{{product.id}}/{{product.imgFile}}_t.jpg" height="25">
<span>{{product.name}}</span> |
<small>Population: {{product.population}}</small>
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
And finally my search component (Typescript file):
import { Component, OnInit } from '@angular/core';
import {FormControl} from '@angular/forms';
import {Product} from '../product';
import {ProductService} from '../product.service';
@Component({
selector: 'app-search-product',
templateUrl: './search-product.component.html',
styleUrls: ['./search-product.component.scss']
})
export class SearchProductComponent implements OnInit {
productCtrl = new FormControl();
products: Product[] = [];
constructor(private productService: ProductService) {
}
ngOnInit() {
this.productCtrl.valueChanges
.subscribe(v => {
this.productService.searchForProduct(v.toString()).valueChanges.subscribe(
({data}) => {
const productsResult: Product[] = [];
data.products_by_p_name_search.forEach((productObj) => {
const product = new Product();
product.id = productObj.id;
product.categoryName = productObj.category_name;
product.name = productObj.name;
product.desc = productObj.desc;
product.quantity = productObj.quantity;
product.yearManufacture = productObj.year_manufacture;
product.imgFile = productObj.image_file;
product.categoryId = productObj.category_id;
product.price = productObj.price;
productsResult.push(product);
});
this.products = productsResult;
});
});
}
}
As far as i see, these lines of code can work, but it might not be the most optimized way to write it. so any information regarding the issues above would be greatly appreciated.
I want to add debounceTime and I can't find exactly where to add it.
You add debounce time[1]where you subscribe to value updates. Your ngOnInit
will look something like this
ngOnInit() {
this.productCtrl.valueChanges
.pipe(
debounceTime(500),
distinctUntilChanged()
)
.subscribe(v => {
...
Don't forget to import {debounceTime} from 'rxjs/operators';
.
I want that empty values won't be searched in the graphQL query
throw a filter( value => value.length > 0)
Your ngOnInit
is now something like
ngOnInit() {
this.productCtrl.valueChanges
.pipe(
debounceTime(500),
distinctUntilChanged(),
filter( value => value.length > 0)
)
.subscribe(v => {
...
I don't use async filter for mat-autocomplete since I put the results inside an array. is that the correct way to go?
I don't know your reasoning behind not using async pipe. This SO answer has a working demo of pipe.