0

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:

  1. I want to add debounceTime and I can't find exactly where to add it.
  2. I want that empty values won't be searched in the graphQL query
  3. I don't use async filter for mat-autocomplete since I put the results inside an array. is that the correct way to go?

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.

Aruna Herath
  • 6,241
  • 1
  • 40
  • 59
ufk
  • 30,912
  • 70
  • 235
  • 386

1 Answers1

3

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.

itaintme
  • 1,575
  • 8
  • 22