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

@libs-ui/components-inputs-search

v0.2.357-9

Published

> Ô nhập liệu tìm kiếm với debounce tự động, hỗ trợ phím Enter, nút xóa nhanh và tùy chỉnh icon linh hoạt.

Downloads

4,178

Readme

@libs-ui/components-inputs-search

Ô nhập liệu tìm kiếm với debounce tự động, hỗ trợ phím Enter, nút xóa nhanh và tùy chỉnh icon linh hoạt.

Giới thiệu

@libs-ui/components-inputs-search là component ô tìm kiếm được xây dựng trên nền @libs-ui/components-inputs-input, bổ sung cơ chế debounce tự động để giảm số lần gọi API khi người dùng đang gõ. Component hỗ trợ phím Enter để kích hoạt tìm kiếm ngay lập tức (với throttle chống spam), nút xóa nội dung nhanh khi bật hasClearSearch, và đầy đủ các tuỳ chỉnh về icon, border, background thông qua searchConfig.

Tính năng

  • Tự động emit outSearch sau khoảng thời gian debounce (mặc định 1000ms) khi người dùng ngừng gõ
  • Emit outSearch ngay lập tức khi nhấn Enter (throttle cùng debounce time để chống spam)
  • Nút xóa nội dung nhanh (hasClearSearch: true) xuất hiện khi ô có nội dung
  • Emit outValueChange mỗi lần gõ phím để lắng nghe thay đổi tức thời
  • Tùy chỉnh icon trái/phải, placeholder, border, background, chiều cao qua searchConfig
  • Hỗ trợ disable, readonly, ignoreAutoComplete
  • Cung cấp outFunctionsControl để điều khiển programmatically (focus, blur, reset)
  • Hoạt động với Angular Signals và ChangeDetectionStrategy.OnPush

Khi nào sử dụng

  • Khi cần ô tìm kiếm tự động gửi yêu cầu sau khi người dùng ngừng gõ (debounce) thay vì gửi mỗi keystroke
  • Khi cần tích hợp tìm kiếm vào thanh lọc dữ liệu, bảng danh sách hoặc dropdown autocomplete
  • Khi cần ô tìm kiếm có nút xóa nhanh để người dùng reset filter dễ dàng
  • Khi cần lắng nghe cả hai luồng: giá trị tức thời (outValueChange) và giá trị đã được debounce (outSearch)

Cài đặt

npm install @libs-ui/components-inputs-search

Import

import { LibsUiComponentsInputsSearchComponent } from '@libs-ui/components-inputs-search';

@Component({
  standalone: true,
  imports: [LibsUiComponentsInputsSearchComponent],
  // ...
})
export class MyComponent {}

Nếu cần dùng interface IInputSearchConfig:

import {
  LibsUiComponentsInputsSearchComponent,
  IInputSearchConfig,
} from '@libs-ui/components-inputs-search';

Ví dụ sử dụng

Ví dụ 1 — Cơ bản

<libs_ui-components-inputs-search
  [searchConfig]="{ placeholder: 'Tìm kiếm khách hàng...' }"
  (outSearch)="handlerSearch($event)">
</libs_ui-components-inputs-search>
handlerSearch(keyword: string): void {
  // keyword đã được trim, chỉ emit sau debounce hoặc khi nhấn Enter
  this.loadData({ search: keyword });
}

Ví dụ 2 — Với placeholder và nút xóa nhanh

<libs_ui-components-inputs-search
  [searchConfig]="{
    placeholder: 'Tìm kiếm khách hàng...',
    hasClearSearch: true
  }"
  (outSearch)="handlerSearch($event)">
</libs_ui-components-inputs-search>
handlerSearch(keyword: string): void {
  // keyword = '' khi người dùng nhấn nút xóa (X)
  this.params.update(p => ({ ...p, search: keyword, page: 1 }));
  this.loadList();
}

Ví dụ 3 — Tùy chỉnh debounce và icon

<libs_ui-components-inputs-search
  [debounceTime]="500"
  [searchConfig]="{
    iconLeftClass: 'libs-ui-icon-filter',
    placeholder: 'Lọc nhanh...',
    noBorder: true,
    backgroundNone: true
  }"
  (outSearch)="handlerFilter($event)">
</libs_ui-components-inputs-search>
handlerFilter(keyword: string): void {
  this.filterKeyword.set(keyword);
}

Ví dụ 4 — Lắng nghe từng keystroke (outValueChange)

<libs_ui-components-inputs-search
  [ignoreAutoComplete]="true"
  (outValueChange)="handlerValueChange($event)"
  (outSearch)="handlerSearch($event)">
</libs_ui-components-inputs-search>
handlerValueChange(keyword: string): void {
  // Emit mỗi lần gõ — dùng để hiển thị gợi ý realtime
  this.suggestionKeyword.set(keyword);
}

handlerSearch(keyword: string): void {
  // Chỉ emit khi nhấn Enter (ignoreAutoComplete = true bỏ qua debounce)
  this.executeSearch(keyword);
}

Ví dụ 5 — Điều khiển programmatically qua FunctionsControl

<libs_ui-components-inputs-search
  [searchConfig]="{ placeholder: 'Tìm kiếm...' }"
  (outFunctionsControl)="handlerFunctionsControl($event)"
  (outSearch)="handlerSearch($event)">
</libs_ui-components-inputs-search>
import { IInputFunctionControlEvent } from '@libs-ui/components-inputs-input';

private searchControl: IInputFunctionControlEvent | undefined;

handlerFunctionsControl(control: IInputFunctionControlEvent): void {
  this.searchControl = control;
}

// Focus ô tìm kiếm từ code
focusSearchInput(): void {
  this.searchControl?.focus();
}

// Reset giá trị từ code
resetSearch(): void {
  this.searchControl?.resetValue();
}

handlerSearch(keyword: string): void {
  this.executeSearch(keyword);
}

@Input()

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | blurTimeOut | number | 600 | Thời gian chờ (ms) trước khi emit sự kiện blur | [blurTimeOut]="300" | | debounceTime | number | 1000 | Thời gian chờ (ms) sau khi người dùng ngừng gõ để emit outSearch | [debounceTime]="500" | | disable | boolean | false | Vô hiệu hóa toàn bộ ô tìm kiếm | [disable]="isLoading()" | | focusTimeOut | number | 600 | Thời gian chờ (ms) trước khi emit sự kiện focus | [focusTimeOut]="300" | | ignoreAutoComplete | boolean | undefined | Nếu true, bỏ qua debounce — chỉ emit outSearch khi nhấn Enter | [ignoreAutoComplete]="true" | | ignoreStopPropagationEvent | boolean | false | Không gọi stopPropagation cho các DOM event bên trong | [ignoreStopPropagationEvent]="true" | | readonly | boolean | false | Chỉ hiển thị, không cho phép nhập liệu | [readonly]="true" | | searchConfig | IInputSearchConfig | {} | Cấu hình chi tiết giao diện ô tìm kiếm (xem bảng IInputSearchConfig) | [searchConfig]="searchConfig()" |

IInputSearchConfig

| Thuộc tính | Type | Mặc định | Mô tả | Ví dụ | |---|---|---|---|---| | backgroundNone | boolean | false | Xóa màu nền của ô input | backgroundNone: true | | classContainerInput | string | '' | Class CSS bổ sung cho phần tử bọc input | classContainerInput: 'rounded-full' | | classCoverInputSearch | string | undefined | Class CSS bổ sung cho lớp ngoài cùng của search | classCoverInputSearch: 'w-64' | | classInclude | string | undefined | Class CSS bổ sung truyền xuống component Input | classInclude: 'border-blue-500' | | defaultHeight | number | 32 | Chiều cao mặc định (px) của ô input | defaultHeight: 36 | | hasClearSearch | boolean | undefined | Hiển thị nút xóa (X) khi ô có nội dung | hasClearSearch: true | | iconLeftClass | string | 'libs-ui-icon-search' | Class icon phía trái | iconLeftClass: 'libs-ui-icon-filter' | | iconRightClass | string | undefined | Class icon phía phải (thêm vào sau icon xóa nếu có) | iconRightClass: 'libs-ui-icon-tooltip-outline' | | noBorder | boolean | false | Ẩn đường viền của ô input | noBorder: true | | placeholder | string | 'i18n_search' | Placeholder của ô input (hỗ trợ i18n key) | placeholder: 'Tìm kiếm...' | | popoverContentIconRight | string | '' | Nội dung popover hiển thị khi hover icon phải | popoverContentIconRight: 'i18n_search_hint' | | value | string | undefined | Giá trị khởi tạo của ô tìm kiếm | value: 'từ khóa ban đầu' |

@Output()

| Output | Type | Mô tả | Handler TS | Binding HTML | |---|---|---|---|---| | (outFocusAndBlur) | IFocusAndBlurEvent | Emit khi ô input được focus hoặc blur, kèm trạng thái và DOM event | handlerFocusAndBlur(e: IFocusAndBlurEvent): void { e.event.stopPropagation(); this.isFocused.set(e.focus); } | (outFocusAndBlur)="handlerFocusAndBlur($event)" | | (outFunctionsControl) | IInputFunctionControlEvent | Emit object chứa các hàm điều khiển input: focus, blur, resetValue, insertContent | handlerFunctionsControl(ctrl: IInputFunctionControlEvent): void { this.searchCtrl = ctrl; } | (outFunctionsControl)="handlerFunctionsControl($event)" | | (outIconLeft) | string | Emit tên event khi người dùng click vào icon bên trái | handlerIconLeft(eventName: string): void { eventName; } | (outIconLeft)="handlerIconLeft($event)" | | (outIconRight) | string | Emit tên event khi người dùng click vào icon bên phải (ngoài hành vi xóa) | handlerIconRight(eventName: string): void { eventName; } | (outIconRight)="handlerIconRight($event)" | | (outSearch) | string | Emit chuỗi tìm kiếm (đã trim) sau debounce hoặc khi nhấn Enter. Emit '' khi người dùng xóa hết hoặc nhấn nút xóa | handlerSearch(keyword: string): void { this.loadData({ search: keyword }); } | (outSearch)="handlerSearch($event)" | | (outValueChange) | string | Emit chuỗi ngay lập tức mỗi khi giá trị input thay đổi (mỗi keystroke) | handlerValueChange(keyword: string): void { this.currentValue.set(keyword); } | (outValueChange)="handlerValueChange($event)" |

Types & Interfaces

import {
  IInputSearchConfig,
} from '@libs-ui/components-inputs-search';

// IInputFunctionControlEvent và IFocusAndBlurEvent được re-export từ:
import {
  IInputFunctionControlEvent,
  IFocusAndBlurEvent,
} from '@libs-ui/components-inputs-input';
export interface IInputSearchConfig {
  classInclude?: string;           // Class CSS bổ sung cho component Input bên trong
  classContainerInput?: string;    // Class CSS cho phần tử bọc input
  placeholder?: string;            // Placeholder (hỗ trợ i18n key)
  value?: string;                  // Giá trị khởi tạo
  noBorder?: boolean;              // Ẩn border
  backgroundNone?: boolean;        // Xóa background
  iconLeftClass?: string;          // Class icon trái (mặc định: 'libs-ui-icon-search')
  iconRightClass?: string;         // Class icon phải
  defaultHeight?: number;          // Chiều cao (px), mặc định: 32
  classCoverInputSearch?: string;  // Class cho wrapper ngoài cùng
  hasClearSearch?: boolean;        // Bật nút xóa nhanh (X)
  popoverContentIconRight?: string; // Nội dung popover icon phải
}

export interface IInputFunctionControlEvent {
  focus: (emitEvent?: boolean) => Promise<void>;
  blur: (emitEvent?: boolean) => Promise<void>;
  resetValue: () => Promise<void>;
  insertContent: (data: string | number) => Promise<void>;
  // Các method khác từ @libs-ui/components-inputs-input
}

export interface IFocusAndBlurEvent {
  focus: boolean;   // true = đang focus, false = đã blur
  event: FocusEvent;
}

Logic ẩn cần biết

Cơ chế debounce và Enter hoạt động độc lập:

  • Khi người dùng gõ: outSearch emit sau debounceTime ms kể từ keystroke cuối.
  • Khi người dùng nhấn Enter: outSearch emit ngay lập tức (có throttle với cùng debounceTime để chống spam).
  • Khi người dùng nhấn Enter trong lúc debounce đang đếm: debounce bị hủy, outSearch chỉ emit 1 lần từ luồng Enter.

Hành vi xóa nội dung (hasClearSearch: true):

  • Khi ô có nội dung, icon phải tự động chuyển thành icon xóa (X).
  • Nhấn X: valueSearch reset về ''outSearch emit '' ngay lập tức (không qua debounce).
  • Khi xóa hết bằng bàn phím: outSearch emit '' sau debounceTime / 2 ms.

ignoreAutoComplete = true:

  • Hoàn toàn vô hiệu hóa luồng debounce.
  • outSearch chỉ emit khi người dùng nhấn Enter.
  • Thích hợp cho các ô tìm kiếm cần người dùng xác nhận trước khi gửi.

Lưu ý quan trọng

⚠️ Debounce mặc định 1000ms: Nếu UX cần phản hồi nhanh hơn (ví dụ filter local), hãy giảm [debounceTime]="300" hoặc [debounceTime]="500".

⚠️ outSearch emit chuỗi rỗng khi xóa: Khi người dùng xóa hết nội dung hoặc nhấn nút X, outSearch sẽ emit ''. Handler phải xử lý trường hợp này (ví dụ: reset filter, load lại toàn bộ danh sách).

⚠️ value trong searchConfig chỉ là giá trị khởi tạo: Sau khi component khởi tạo, thay đổi searchConfig().value từ bên ngoài không tự động cập nhật giao diện. Dùng FunctionsControl.resetValue() hoặc FunctionsControl.insertContent() để cập nhật programmatically.

⚠️ outValueChange vs outSearch: Dùng outValueChange khi cần phản hồi tức thì (ví dụ: highlight từ khóa, đếm ký tự). Dùng outSearch cho các tác vụ tốn tài nguyên (gọi API).