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 🙏

© 2026 – Pkg Stats / Ryan Hefner

ngx-st-search-selects

v18.0.1

Published

- [Overview](#overview) - [Installation](#installation) - [Basic Usage](#basic-usage) - [Inputs](#inputs) - [Outputs](#outputs) - [Usage Examples](#usage-examples) - [Best Practices](#best-practices)

Downloads

310

Readme

Search Select Component - Complete Documentation

Table of Contents


Overview

The ngx-st-search-select component is a searchable dropdown select with virtual scrolling support. Features include:

  • Searchable dropdown with autocomplete
  • Virtual scrolling for large datasets
  • Custom option labels from multiple fields
  • Flexible filtering by multiple fields
  • Angular Forms integration (model or FormControl)
  • Empty option support
  • Disabled state

Installation

npm install ngx-st-search-selects

Import the module:

import { NgxStSearchSelectsModule } from 'ngx-st-search-selects';

@NgModule({
  imports: [NgxStSearchSelectsModule]
})
export class AppModule { }

Basic Usage

With ngModel

<ngx-st-search-select
  selectLabel="Select User"
  optionValueField="id"
  optionLabelFields="firstName,lastName"
  filteredByFields="firstName,lastName,email"
  [options]="users"
  [(model)]="selectedUserId">
</ngx-st-search-select>

With FormControl

// Component
userControl = new FormControl(null);
<ngx-st-search-select
  selectLabel="Select User"
  optionValueField="id"
  optionLabelFields="firstName,lastName"
  selectBindType="control"
  [selectFormControl]="userControl"
  [options]="users">
</ngx-st-search-select>

Inputs

selectLabel

  • Type: string
  • Default: undefined
  • Description: Label text displayed above the select.
  • Example:
    selectLabel="Select User"
    selectLabel="Choose Category"

optionValueField

  • Type: string
  • Default: undefined
  • Description: Property name to use as the value for options.
  • Example:
    optionValueField="id"
    optionValueField="code"

optionLabelFields

  • Type: string
  • Default: undefined
  • Description: Comma-separated list of properties to display in the dropdown. Fields are concatenated with spaces.
  • Example:
    optionLabelFields="name"
    optionLabelFields="firstName,lastName"
    optionLabelFields="code,name,description"

filteredByFields

  • Type: string
  • Default: undefined
  • Description: Comma-separated list of properties to search through when filtering. If not provided, uses default filter method.
  • Example:
    filteredByFields="name"
    filteredByFields="firstName,lastName,email"
    filteredByFields="code,name,description,category"

model

  • Type: model signal
  • Default: undefined
  • Description: Two-way binding model for the selected value.
  • Example:
    [(model)]="selectedValue"

modelChange

  • Type: (e: any) => void
  • Default: undefined
  • Description: Custom change handler function. Alternative to using the output.
  • Example:
    onModelChange = (value: any) => {
      console.log('Changed:', value);
    }
    [modelChange]="onModelChange"

selectFormControl

  • Type: FormControl
  • Default: undefined
  • Description: FormControl to bind when using selectBindType="control".
  • Example:
    userControl = new FormControl(null);
    [selectFormControl]="userControl"

required

  • Type: boolean
  • Default: false
  • Description: Makes the select required (adds asterisk to label).
  • Example:
    [required]="true"

selectBindType

  • Type: 'model' | 'control'
  • Default: 'model'
  • Description: Type of binding to use.
    • 'model': Use with model input
    • 'control': Use with selectFormControl input
  • Example:
    selectBindType="model"
    selectBindType="control"

searchLabel

  • Type: string
  • Default: 'Search'
  • Description: Placeholder text for the search input.
  • Example:
    searchLabel="Search users..."
    searchLabel="Type to filter..."

showEmptyOption

  • Type: boolean
  • Default: true
  • Description: Shows an empty option at the top of the list (for clearing selection).
  • Example:
    [showEmptyOption]="false"

useVirtualScrollOptions

  • Type: boolean
  • Default: false
  • Description: Enables virtual scrolling for better performance with large datasets.
  • Example:
    [useVirtualScrollOptions]="true"

options

  • Type: any[]
  • Default: []
  • Description: Array of options to display in the dropdown.
  • Example:
    users = [
      { id: 1, firstName: 'John', lastName: 'Doe', email: '[email protected]' },
      { id: 2, firstName: 'Jane', lastName: 'Smith', email: '[email protected]' }
    ];
    [options]="users"

disabled

  • Type: boolean
  • Default: false
  • Description: Disables the select dropdown.
  • Example:
    [disabled]="isReadOnly"
    [disabled]="true"

Outputs

selectDataChanged

  • Type: any
  • Description: Emitted when the selected value changes. Contains the selected option object.
  • Example:
    (selectDataChanged)="onSelectionChange($event)"
      
    onSelectionChange(selected: any): void {
      console.log('Selected:', selected);
    }

Usage Examples

Example 1: Basic User Selection

// Component
@Component({
  selector: 'app-user-select',
  template: `
    <ngx-st-search-select
      selectLabel="Select User"
      searchLabel="Search users..."
      optionValueField="id"
      optionLabelFields="firstName,lastName"
      filteredByFields="firstName,lastName,email"
      [options]="users"
      [(model)]="selectedUserId"
      (selectDataChanged)="onUserSelected($event)">
    </ngx-st-search-select>
    
    <p *ngIf="selectedUser">
      Selected: {{ selectedUser.firstName }} {{ selectedUser.lastName }}
    </p>
  `
})
export class UserSelectComponent {
  selectedUserId: number;
  selectedUser: User;
  
  users: User[] = [
    { id: 1, firstName: 'John', lastName: 'Doe', email: '[email protected]' },
    { id: 2, firstName: 'Jane', lastName: 'Smith', email: '[email protected]' },
    { id: 3, firstName: 'Bob', lastName: 'Johnson', email: '[email protected]' }
  ];
  
  onUserSelected(user: User): void {
    this.selectedUser = user;
    console.log('User selected:', user);
  }
}

Example 2: With FormControl and Validation

// Component
@Component({
  selector: 'app-form-select',
  template: `
    <form [formGroup]="myForm">
      <ngx-st-search-select
        selectLabel="Category"
        searchLabel="Search categories..."
        optionValueField="id"
        optionLabelFields="name"
        filteredByFields="name,code"
        selectBindType="control"
        [selectFormControl]="myForm.get('categoryId')"
        [options]="categories"
        [required]="true">
      </ngx-st-search-select>
      
      <mat-error *ngIf="myForm.get('categoryId')?.hasError('required')">
        Category is required
      </mat-error>
      
      <button [disabled]="myForm.invalid" (click)="submit()">
        Submit
      </button>
    </form>
  `
})
export class FormSelectComponent {
  categories = [
    { id: 1, name: 'Electronics', code: 'ELEC' },
    { id: 2, name: 'Clothing', code: 'CLTH' },
    { id: 3, name: 'Food', code: 'FOOD' }
  ];
  
  myForm = this.fb.group({
    categoryId: [null, Validators.required]
  });
  
  constructor(private fb: FormBuilder) {}
  
  submit(): void {
    if (this.myForm.valid) {
      console.log('Form data:', this.myForm.value);
    }
  }
}

Example 3: Country/State Selection

// Component
@Component({
  selector: 'app-location-select',
  template: `
    <div class="location-selectors">
      <ngx-st-search-select
        selectLabel="Country"
        searchLabel="Search countries..."
        optionValueField="code"
        optionLabelFields="name"
        filteredByFields="name,code"
        [options]="countries"
        [(model)]="selectedCountry"
        (selectDataChanged)="onCountryChange($event)">
      </ngx-st-search-select>
      
      <ngx-st-search-select
        *ngIf="selectedCountry"
        selectLabel="State/Province"
        searchLabel="Search states..."
        optionValueField="code"
        optionLabelFields="name"
        filteredByFields="name,code"
        [options]="states"
        [(model)]="selectedState">
      </ngx-st-search-select>
    </div>
  `
})
export class LocationSelectComponent {
  selectedCountry: string;
  selectedState: string;
  
  countries = [
    { code: 'US', name: 'United States' },
    { code: 'CA', name: 'Canada' },
    { code: 'UK', name: 'United Kingdom' }
  ];
  
  states: any[] = [];
  
  private statesByCountry = {
    'US': [
      { code: 'CA', name: 'California' },
      { code: 'NY', name: 'New York' },
      { code: 'TX', name: 'Texas' }
    ],
    'CA': [
      { code: 'ON', name: 'Ontario' },
      { code: 'QC', name: 'Quebec' },
      { code: 'BC', name: 'British Columbia' }
    ]
  };
  
  onCountryChange(country: any): void {
    this.selectedState = null;
    this.states = this.statesByCountry[country.code] || [];
  }
}

Example 4: Product Selection with Multiple Display Fields

// Component
@Component({
  selector: 'app-product-select',
  template: `
    <ngx-st-search-select
      selectLabel="Select Product"
      searchLabel="Search products..."
      optionValueField="id"
      optionLabelFields="code,name,category"
      filteredByFields="code,name,category,manufacturer"
      [options]="products"
      [(model)]="selectedProductId"
      (selectDataChanged)="onProductSelected($event)">
    </ngx-st-search-select>
    
    <div *ngIf="selectedProduct" class="product-details">
      <h3>{{ selectedProduct.name }}</h3>
      <p>Code: {{ selectedProduct.code }}</p>
      <p>Price: {{ selectedProduct.price | currency }}</p>
    </div>
  `
})
export class ProductSelectComponent {
  selectedProductId: number;
  selectedProduct: Product;
  
  products: Product[] = [
    { 
      id: 1, 
      code: 'PROD-001', 
      name: 'Widget Pro', 
      category: 'Tools',
      manufacturer: 'Acme Corp',
      price: 99.99
    },
    { 
      id: 2, 
      code: 'PROD-002', 
      name: 'Super Gadget', 
      category: 'Electronics',
      manufacturer: 'Tech Inc',
      price: 149.99
    }
  ];
  
  onProductSelected(product: Product): void {
    this.selectedProduct = product;
  }
}

Example 5: Virtual Scrolling for Large Datasets

// Component
@Component({
  selector: 'app-large-select',
  template: `
    <ngx-st-search-select
      selectLabel="Select Item"
      searchLabel="Search from 10,000 items..."
      optionValueField="id"
      optionLabelFields="name"
      filteredByFields="name,description"
      [options]="largeDataset"
      [useVirtualScrollOptions]="true"
      [(model)]="selectedId">
    </ngx-st-search-select>
  `
})
export class LargeSelectComponent implements OnInit {
  selectedId: number;
  largeDataset: any[] = [];
  
  ngOnInit(): void {
    // Generate 10,000 items
    this.largeDataset = Array.from({ length: 10000 }, (_, i) => ({
      id: i + 1,
      name: `Item ${i + 1}`,
      description: `Description for item ${i + 1}`
    }));
  }
}

Example 6: Dynamic Options Loading

// Component
@Component({
  selector: 'app-dynamic-select',
  template: `
    <ngx-st-search-select
      selectLabel="Select Department"
      searchLabel="Search departments..."
      optionValueField="id"
      optionLabelFields="name"
      filteredByFields="name,code"
      [options]="departments"
      [disabled]="loading"
      [(model)]="selectedDepartmentId"
      (selectDataChanged)="onDepartmentChange($event)">
    </ngx-st-search-select>
    
    <mat-spinner *ngIf="loading" diameter="30"></mat-spinner>
  `
})
export class DynamicSelectComponent implements OnInit {
  selectedDepartmentId: number;
  departments: Department[] = [];
  loading = false;
  
  constructor(private departmentService: DepartmentService) {}
  
  ngOnInit(): void {
    this.loadDepartments();
  }
  
  loadDepartments(): void {
    this.loading = true;
    this.departmentService.getAll().subscribe(
      departments => {
        this.departments = departments;
        this.loading = false;
      },
      error => {
        console.error('Error loading departments:', error);
        this.loading = false;
      }
    );
  }
  
  onDepartmentChange(department: Department): void {
    console.log('Department selected:', department);
  }
}

Example 7: Without Empty Option

// Component
@Component({
  selector: 'app-required-select',
  template: `
    <ngx-st-search-select
      selectLabel="Status"
      optionValueField="id"
      optionLabelFields="name"
      [options]="statuses"
      [showEmptyOption]="false"
      [required]="true"
      [(model)]="selectedStatus">
    </ngx-st-search-select>
  `
})
export class RequiredSelectComponent implements OnInit {
  selectedStatus: number;
  
  statuses = [
    { id: 1, name: 'Active' },
    { id: 2, name: 'Inactive' },
    { id: 3, name: 'Pending' }
  ];
  
  ngOnInit(): void {
    // Set default value
    this.selectedStatus = 1;
  }
}

Example 8: Cascading Selects

// Component
@Component({
  selector: 'app-cascading-select',
  template: `
    <form [formGroup]="form">
      <ngx-st-search-select
        selectLabel="Category"
        optionValueField="id"
        optionLabelFields="name"
        selectBindType="control"
        [selectFormControl]="form.get('categoryId')"
        [options]="categories"
        (selectDataChanged)="onCategoryChange($event)">
      </ngx-st-search-select>
      
      <ngx-st-search-select
        selectLabel="Subcategory"
        optionValueField="id"
        optionLabelFields="name"
        selectBindType="control"
        [selectFormControl]="form.get('subcategoryId')"
        [options]="subcategories"
        [disabled]="!form.get('categoryId')?.value"
        (selectDataChanged)="onSubcategoryChange($event)">
      </ngx-st-search-select>
      
      <ngx-st-search-select
        selectLabel="Product"
        optionValueField="id"
        optionLabelFields="name"
        selectBindType="control"
        [selectFormControl]="form.get('productId')"
        [options]="products"
        [disabled]="!form.get('subcategoryId')?.value">
      </ngx-st-search-select>
    </form>
  `
})
export class CascadingSelectComponent {
  categories = [...];
  subcategories: any[] = [];
  products: any[] = [];
  
  form = this.fb.group({
    categoryId: [null],
    subcategoryId: [null],
    productId: [null]
  });
  
  constructor(private fb: FormBuilder) {}
  
  onCategoryChange(category: any): void {
    this.form.patchValue({ subcategoryId: null, productId: null });
    this.loadSubcategories(category.id);
  }
  
  onSubcategoryChange(subcategory: any): void {
    this.form.patchValue({ productId: null });
    this.loadProducts(subcategory.id);
  }
  
  loadSubcategories(categoryId: number): void {
    // Load subcategories
  }
  
  loadProducts(subcategoryId: number): void {
    // Load products
  }
}

Best Practices

  1. Specify search fields for better filtering:

    filteredByFields="name,code,description"
  2. Use virtual scrolling for large datasets:

    [useVirtualScrollOptions]="true"
  3. Provide clear labels:

    selectLabel="Select User"
    searchLabel="Search by name or email..."
  4. Use FormControl for forms:

    selectBindType="control"
    [selectFormControl]="myControl"
  5. Handle empty selections:

    [showEmptyOption]="true"
  6. Display multiple fields when helpful:

    optionLabelFields="code,name,category"

Component Behavior

  • Search: Type in the search box to filter options
  • Filtering: Searches through fields specified in filteredByFields
  • Selection: Click an option to select it
  • Clear: Select empty option (if enabled) to clear selection
  • Virtual Scroll: Renders only visible items for performance

This documentation covers all inputs, outputs, and usage patterns for the Search Select component.