File

src/app/search-ui/search/search.component.ts

Implements

OnInit

Metadata

selector app-search
styleUrls search.component.css
templateUrl ./search.component.html

Index

Properties
Methods

Constructor

constructor(search: AlgoliaService, snackBar: MatSnackBar)
Parameters :
Name Type Optional
search AlgoliaService no
snackBar MatSnackBar no

Methods

filterByCategory
filterByCategory(category: Category)
Parameters :
Name Type Optional
category Category no
Returns : void
ngOnInit
ngOnInit()
Returns : void
onScroll
onScroll()
Returns : void
onSearchInputChange
onSearchInputChange(query: string)
Parameters :
Name Type Optional
query string no
Returns : void
onSearchInputClear
onSearchInputClear()
Returns : void
onSortOptionChange
onSortOptionChange(changeEvent: MatButtonToggleChange)
Parameters :
Name Type Optional
changeEvent MatButtonToggleChange no
Returns : void
openSnackBar
openSnackBar()
Returns : void

Properties

Private _applications
_applications: Application[]
Type : Application[]
applicationsCount
applicationsCount: number
Type : number
Default value : 0
hitsPerPage
hitsPerPage: number
Type : number
Default value : 20
isInfiniteScrollRequested
isInfiniteScrollRequested: boolean
Type : boolean

An internal flag used when an infinite scroll has be initiated.

lastResultCount
lastResultCount:
Default value : Infinity

Keep track of the previous count (number of hits).

searchCategories
searchCategories: Category[]
Type : Category[]

The categories (facets) computed for each search result.

sortOption
sortOption: string
Type : string
Default value : 'rating_desc'

Accessors

applications
getapplications()
setapplications(value: [])

Reseting the state of the "appliations" property will automatically clear the list of the categories reset the scroll behavior and reset the last count.

Parameters :
Name Type Optional
value [] no
Returns : void
import { Component, OnInit, AfterContentInit } from '@angular/core';
import { Observable, PartialObserver, Subject } from 'rxjs';
import { filter, switchMap, share, switchMapTo } from 'rxjs/operators';
import { MatSnackBar, MatButtonToggleChange } from '@angular/material';
import { AlgoliaService } from '@app/core/algolia/algolia.service';
import { Category } from '../facets/category/category.component';
import { SearchService, Application } from './../search.service';

@Component({
  selector: 'app-search',
  templateUrl: './search.component.html',
  styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {
  hitsPerPage = 20;
  applicationsCount = 0;
  sortOption = 'rating_desc';
  private _applications: Application[];

  /**
   * Reseting the state of the "appliations" property will automatically clear the list of the categories
   * reset the scroll behavior and reset the last count.
   *
   */
  set applications(value: Application[]) {
    if (!value || value.length === 0) {
      // reset the component local state
      this.searchCategories = [];
      this.isInfiniteScrollRequested = false;
      this.lastResultCount = Infinity;
    }

    this._applications = value;
  }

  get applications() {
    return this._applications;
  }

  /**
   * The categories (facets) computed for each search result.
   */
  searchCategories: Category[];

  /**
   * An internal flag used when an infinite scroll has be initiated.
   */
  isInfiniteScrollRequested: boolean;

  /**
   * Keep track of the previous count (number of hits).
   */
  lastResultCount = Infinity;

  constructor(private search: AlgoliaService, private snackBar: MatSnackBar) {
    this.applications = [];
    this.searchCategories = [];
    this.search.setQueryParameter({
      hitsPerPage: this.hitsPerPage
    });
  }

  ngOnInit() {
    const handleResultSubscription = content => {
      this.applicationsCount = content.nbHits;

      const categoriesFacet = content.getFacetValues('category') as any[];
      if (categoriesFacet.length > 1) {
        this.searchCategories = categoriesFacet;
      }

      this.lastResultCount = content.hits.length;

      if (this.isInfiniteScrollRequested) {
        this.applications = this.applications.concat(content.hits);
      } else {
        this.applications = content.hits;
      }

      this.isInfiniteScrollRequested = false;
    };

    this.search.searchState.result$.subscribe(handleResultSubscription);

    this.search.searchState.error$.subscribe(content => {
      this.applications = [];
    });
    this.search.searchState.search$.subscribe(content => {
      if (this.isInfiniteScrollRequested) {
        this.openSnackBar();
      }
    });
    this.search.searchState.change$.subscribe(content => {});
  }

  onSearchInputChange(query: string) {
    this.search.sortByRatingDesc(query);
  }

  filterByCategory(category: Category) {
    this.search.toggleFacetRefinement({
      name: 'category',
      query: category.name
    });
  }

  onSearchInputClear() {
    this.applications = [];
  }

  onScroll() {
    if (this.lastResultCount >= this.hitsPerPage && this.applications.length > 0) {
      this.isInfiniteScrollRequested = true;
      this.search.nextPage();
    }
  }

  openSnackBar() {
    this.snackBar.open('Loading more content...', '', {
      duration: 500
    });
  }

  onSortOptionChange(changeEvent: MatButtonToggleChange) {
    switch (changeEvent.value) {
      case 'rating_desc':
        this.search.sortByRatingDesc();
        break;
      case 'price_asc':
        this.search.sortByPriceAsc();
        break;
      case 'relevance_desc':
      default:
        this.search.sortByRelevance();
    }
  }
}
<mat-card class="card" appInfiniteScroll (scroll)="onScroll()">
  <mat-card-header>
    <a class="card_algolia-credits" href="https://www.algolia.com/product" target="__blank" aria-label="Powered by Algolia">
      <p>Powered by</p>
    </a>
    <app-search-input class="card_search-input" (clear)="onSearchInputClear()" (query)="onSearchInputChange($event)"></app-search-input>

  </mat-card-header>
  <mat-card-content class="card_content" [class.no-result]="applications.length === 0">

    <div class="card_sorting-options">

      <mat-button-toggle-group (change)="onSortOptionChange($event)" #group="matButtonToggleGroup" *ngIf="applications.length > 0">
        <mat-button-toggle [checked]="sortOption" value="relevance_desc">
          Most Relevant
        </mat-button-toggle>
        <mat-button-toggle [checked]="sortOption" value="price_asc">
          Lowest Price
        </mat-button-toggle>
        <mat-button-toggle [checked]="sortOption" value="rating_desc">
          Most Popular
        </mat-button-toggle>
      </mat-button-toggle-group>
    </div>

    <mat-expansion-panel *ngIf="searchCategories.length > 0">
      <mat-expansion-panel-header>
        <mat-panel-title>
          Categories
        </mat-panel-title>
      </mat-expansion-panel-header>

      <app-category (selectionChanged)="filterByCategory($event)" [categories]="searchCategories"></app-category>

    </mat-expansion-panel>

    <app-search-result *ngIf="applications.length > 0" [entries]="applications"></app-search-result>

  </mat-card-content>
</mat-card>

<router-outlet></router-outlet>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""