npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@npcz/ngx-search-bar

v0.0.2

Published

Angular component for a customizable material search bar

Downloads

7

Readme

@npcz/ngx-search-bar

An angular material custom component that implements a search bar. The bar has the usual input field, a search button and can optionally have the following additional features:

  • automatic highlighting on hover, focus or both, with the highlight style being configurable (background, shadow or outline)
  • a clear button that shows only when the search input is not empty and can be clicked to clear the input field
  • a select component that can be used to chose a search category to restrict the data source used for search results
  • ability to connect the search field to an angular material autocomplete component provided by the host of the search bar

Installation

npm install @npcz/ngx-search-bar --save

or

yarn add @npcz/ngx-search-bar

Basic Usage

1. Import the SearchBarModule

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { SearchBarModule } from '@npcz/ngx-search-bar';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, SearchBarModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

2. Add the configuration properties to the component

Specify the highlighting style you want to be applied by defining a variable in the component file of type HighlightStyleConfig

type HighlighStyle = 'shadow' | 'outline' | 'background' | 'none';
type HighlightStyleConfig = {
  hover?: HighlighStyle;
  focus?: HighlighStyle;
};
import { Component } from '@angular/core';
import { HighlightStyleConfig } from '@npcz/ngx-highlight';

@Component({
  selector: 'exmp-app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  readonly highlightStyle: HighlightStyleConfig = {
    hover: 'background',
    focus: 'outline',
  };

  // categories can be provided through a Service or any other suitable source
  // in a real application
  readonly categories = [
    'All products',
    'Health',
    'Computers & Accessories',
    'Electronics',
    'Home & Kitchen',
  ];
}

3. Include a hc-search-bar component in the template

<hc-search-bar
  [highlightStyle]="highlightStyle"
  [categoryList]="categories"
  category="All Products"
  clearButton="true"
>
</hc-search-bar>

4. Include the theming support styles in your app

ngx-search-bar uses SASS styling and provides mixins that can be integrated into and angular material application theme. Simply follow the instructions for Angular Material Theming. The theme file is located in node_modules/@npcz/ngx-search-bar/src/styles.

Adding search suggestions with autocomplete

The component has zero dependencies on services or providers from the application to implement search related functions. Instead it expects the host component to configure it following parent->child communication model with Input properties. All child->parent communication uses Observables.

Here is an example of a host component providing the autocomplete implementation to the search bar and using its observables:

<hc-search-bar
  [highlightStyle]="highlightStyle"
  [categoryList]="categories"
  category="All Products"
  clearButton="true"
>
</hc-search-bar>
<!-- 
  The autocomplete template is provided by the host to completely decouple
  the search bar from the search implementation.
-->
<mat-autocomplete #auto="matAutocomplete" autoActiveFirstOption="true">
  <mat-option *ngIf="isLoading" class="is-loading"
    ><mat-spinner diameter="40"></mat-spinner
  ></mat-option>
  <ng-container *ngIf="!isLoading">
    <mat-option
      *ngFor="let suggestion of searchSuggestions | async"
      [value]="suggestion"
    >
      <span>{{ suggestion }}</span>
    </mat-option>
  </ng-container>
</mat-autocomplete>
export class GlobalSearchBarComponent implements AfterViewInit, OnDestroy {
  @ViewChild(MatAutocomplete) private _autocomplete: MatAutocomplete;
  @ViewChild(SearchBarComponent) private _searchBar: SearchBarComponent;

  // Automatic unsubscription when the component is destroyed
  // We don't want an emitted value, just the fact of emitting is enough
  private _ngUnsubscribe$ = new Subject<never>();

  private _searchSuggestions = new BehaviorSubject<string[]>([]);
  searchSuggestions: Observable<
    string[]
  > = this._searchSuggestions.asObservable();

  categories = [
    'All products',
    'Health',
    'Computers & Accessories',
    'Electronics',
    'Home & Kitchen',
  ];

  isLoading = false;

  constructor(private _http: HttpClient, private _cd: ChangeDetectorRef) {
  }

  // Hook into the search bar event observables after the view is initialized
  // and the @ViewChild bindings become valid
  ngAfterViewInit(): void {
    this._searchBar.autoComplete = this._autocomplete;
    this._cd.detectChanges();

    // Get involved everytime a change to the selected category or to the
    // search input field occurs.
    // => load search suggestions here
    this._searchBar.changes
      .pipe(
        debounceTime(300),
        map((value) => {
          if (!value || !value.query || value.query.length == 0) {
            // Reset the search suggestions
            this._searchSuggestions.next([]);
          } else {
            this._loadSearchSuggestion(value);
          }
        }),
        takeUntil(this._ngUnsubscribe$)
      )
      .subscribe();

    // Know when the search needs to be done (user clicked the search button or
    // hit the 'Enter' key)
    this._searchBar.search
      .pipe(takeUntil(this._ngUnsubscribe$))
      .subscribe((value) => {
        console.debug('submit: ', value);
        // Reset the search suggestions
        this._searchSuggestions.next([]);
      });
  }

  ngOnDestroy(): void {
    this._ngUnsubscribe$.next();
    this._ngUnsubscribe$.complete();
  }

  // Implementation of the search suggestions.
  // Example using goolge search suggestions rest API
  private _loadSearchSuggestion(searchOptions): void {
    const params = new HttpParams();
    params.set('output', 'firefox');
    params.set('q', searchOptions.query);

    console.debug('loading search suggestions: ', searchOptions);
    this.isLoading = true;
    this._http
      .get(
        '/complete/search?output=firefox&q=' +
          encodeURI(searchOptions.query) +
          '&hl=en',
        {
          params: params,
        }
      )
      .pipe(
        map((res) => res[1]),
        take(1),
        catchError(() => {
          this._searchSuggestions.next([]);
          this.isLoading = false;
          return throwError('Failed to get search suggestions.');
        })
      )
      .subscribe((suggestions) => {
        this._searchSuggestions.next(suggestions);
        this.isLoading = false;
      });
  }
  private handleError(error: HttpErrorResponse) {
    if (error.error instanceof ErrorEvent) {
      // A client-side or network error occurred. Handle it accordingly.
      console.error('An error occurred:', error.error.message);
    } else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong,
      console.error(
        `Backend returned code ${error.status}, ` + `body was: ${error.error}`
      );
    }
    // return an observable with a user-facing error message
    return throwError('Something bad happened; please try again later.');
  }

Properties

| Property | Type | Default | Description | | ---------------- | ---------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | placeholder | string | none | Placeholder text for the search input field | | clearButton | boolean | false | Adds a 'clear input' button when true | | disabled | boolean | false | Makes the search bar 'disabled' | | highlightStyle | HighlightStyleConfig | { hover: 'background', focus: 'outline' } | Specifies whether and how the search bar style will change when it is hovered or focused | | categoryList | string[] | undefined | When set to a valid value, this will add a category selection control and a menu with the values in the list to the search bar | | category | string | undefined | The currently selected category from the categoryList | | autoComplete | MatAutoComplete | undefined | The angular material autocomplete component to be used by the search bar for search suggestions. If undefined, no search suggestions functionality will be provided. See example for how to add search suggestions to the search bar |

Events

| Event | Type | Description | | --------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | changes | SearchQueryData | Triggered any time the category or the search input field value changes. Event details will contain the category (optional) and the search input field values | | search | SearchQueryData | Triggered when a search must be initiated. Event details will contain the category (optional) and the search query |

Methods

| Method | Description | | ----------- | -------------------------------------------------------------------------------------- | | clear() | Clear the search input field | | enable() | Enable/activate the search bar | | disable() | Disable/deactivate the search bar | | focus() | Set focus the search bar, which will automatically set focus to the search input field |