컴포넌트/필드 컴포넌트

Filterbox (필터박스)

VanillaFront 2026. 9. 10. 15:28

Va.Filterbox — 타이핑으로 실시간 필터링되는 드롭다운

Va.Combobox가 "옵션에서 선택"이라면, Va.Filterbox는 "옵션이 많을 때 타이핑으로 좁혀 찾아 선택" 하는 컴포넌트입니다. 코드 구조는 Combobox와 판박이지만, 자유 입력 + 실시간 필터링 로직이 추가되어 있어 옵션이 수십·수백 개일 때 진가를 발휘합니다.

  • 클래스: Va.Filterbox  va_component.js:2841
  • short name: filterbox
  • 상속: Va.PureField (Combobox와 형제)
  • isContainer: true
  • 베이스 CSS: va-filterbox (팝업은 va-menu-pop)
  • 소스 크기: 약 1632줄 — Combobox와 함께 최대 크기

 

1. 기본 사용

{
    tagName: 'filterbox',
    data: [
        { key: 'US', display: 'United States' },
        { key: 'KR', display: 'South Korea' },
        { key: 'JP', display: 'Japan' },
        { key: 'CN', display: 'China' }
        // ... 200개국
    ],
    filterKeys: ['display'],       // display 필드로 필터링
    isFilterRuntime: true,         // 타이핑마다 실시간 필터
    value: 'KR',
    onSelect: 'onCountrySelect'
}

필드에 "kor"을 치면 팝업 리스트가 "Korea" 포함 항목만 표시됩니다.


2. Va.Combobox와의 차이

두 컴포넌트는 소스가 거의 판박이라 차이만 정확히 아는 게 실용적입니다.

항목Va.ComboboxVa.Filterbox

필드 편집 readonly (팝업 조작만) 자유 입력 가능 — 타이핑 허용
필터링 로직 없음 filter() 메서드로 데이터 좁힘
filterKeys ✓ (필터 대상 필드명 배열)
isFilterRuntime ✓ (true면 타이핑마다 자동 필터)
Enter 키 동작 팝업 열기/선택 Enter로 필터 실행 + 팝업 열기
↓ 화살표 시 팝업 열림 + 첫 항목 포커스 팝업 열려 있으면 첫 항목 포커스만
rowHeight 기본 34 30 (약간 얇음)
CSS 클래스 va-input va-filterbox

한 줄 요약: "옵션이 많을 때 타이핑으로 찾는 콤보박스."


3. Filterbox 전용 속성

Combobox 속성 전체 + 필터 관련 3개 추가:

속성기본값설명

filterKeys ['display'] 필터링 대상 필드명 배열. 여러 필드에서 매칭하려면 ['key', 'display', 'name'] 같이
isFilterRuntime false true면 타이핑할 때마다 자동 필터 (실시간). false면 Enter 눌러야 필터
editable false 자유 입력 데이터로도 값 확정 허용

나머지 속성(data, key, display, template, multiSelect, popMaxHeight, popWidth, addCheckAll, dataMode 등)은 Combobox와 동일.


4. filterKeys — 어떤 필드에서 검색할지

{
    tagName: 'filterbox',
    filterKeys: ['name', 'email', 'department'],   // 3개 필드 중 아무거나 매칭
    data: [
        { key: '1', name: '홍길동', email: 'hong@ex.com', department: '개발' },
        { key: '2', name: '김철수', email: 'kim@ex.com', department: '기획' }
    ]
}

사용자가 "hong" 치면 email로 매칭, "개발" 치면 department로 매칭. 실무에서 자주 쓰는 패턴.


5. isFilterRuntime — 실시간 vs Enter

두 모드의 UX 차이:

isFilterRuntime: false (기본)

  • 사용자가 타이핑 → 필드에만 텍스트 반영
  • Enter 눌러야 필터 실행 + 팝업 표시
  • 이유: 대량 데이터에서 매 keystroke 필터링 부담 방지

isFilterRuntime: true

  • 사용자가 타이핑 → 100ms debounce 후 자동 필터 (va_component.js:3177-3182)
  • 즉각적인 UX, 소량~중량 데이터에 적합
// 실시간 필터 (수백 건까지)
{ tagName: 'filterbox', isFilterRuntime: true, data: [...] }

// 대량 데이터, Enter로만 (수천 건)
{ tagName: 'filterbox', data: [...] }

6. 필터 로직 (filter() 메서드)

filter(inputValue){
    this.dataManager.filter((item) => {
        for(let i=0; i < this.filterKeys.length; i++){
            if(item[this.filterKeys[i]].indexOf(inputValue) != -1){
                return true;   // 하나라도 매칭되면 표시
            }
        }
        return false;
    });
    this.applyData();
}

특징:

  • 부분 문자열 매칭 (indexOf !== -1) — 대소문자 구분함, 정규식 없음
  • 필드값이 null이면 에러 발생 위험  null.indexOf 호출. 데이터에 빈 값 있으면 방어 필요
  • DataManager.filter() 위임 — 원본 데이터는 유지되고 표시만 좁혀짐
  • clearFilter()로 필터 해제 가능

⚠️ 한글 초성 검색, 대소문자 무시, 정규식 매칭은 자동으로 안 됨. 필요하면 filter() 메서드를 오버라이드하거나 데이터를 미리 가공.


7. 이벤트 (Combobox와 거의 동일)

이벤트시그니처발생 시점

select (component, element, listItem, data, key, display, evt) 항목 선택 시
filterboxItemClick (component, element, row, data, rowIndex, row, evt) 리스트 아이템 클릭 (Combobox의 listItemClick에 해당)
filterboxItemContextmenu 리스트 아이템 우클릭  
beforePop / afterPop / hidePop 팝업 표시  
expand / collapse 팝업 확장  
focus / blur / click / change 표준  

⚠️ 이벤트 이름이 Combobox의 listItemClick이 아니라 filterboxItemClick 인 게 차이. 코드 옮길 때 주의.


8. 키보드 조작

키동작

타이핑 isFilterRuntime:true면 자동 필터. 아니면 텍스트만 입력됨
Enter 필터 실행 + 팝업 열기
↓ (ArrowDown) 팝업 열려 있으면 첫 항목 포커스
Tab 값이 비어 있으면 자동 클리어. 아니면 다음 필드로
Esc 팝업 닫기
↑↓ (팝업 내) 항목 이동
Enter (팝업 내) 선택 확정

9. 메서드

Combobox의 메서드에 필터 관련 하나 추가:

값 관리

메서드설명

getValue() 선택된 값 (single/multi에 따라 문자열 또는 배열)
setValue(value) 값 세팅
getSelectedData() 선택된 데이터 전체 객체

필터 (Filterbox 전용)

메서드설명

filter(inputValue) 프로그램적으로 필터 실행

데이터 (Combobox와 동일)

setData, getData, addData, insertData, modifyData, removeData, moveData, selectData, selectFirstData 등 전부 동일.

팝업 / 상태

메서드설명

showFilterboxPop(evt) / hideFilterboxPop() 팝업 제어 (Combobox는 showComboboxPop 등)
setDisabled(bool) / setReadOnly(bool) 상태
focus() / blur() 포커스

10. 내부 구조

Combobox와 거의 동일하지만 readonly 속성이 제거되어 사용자가 필드에 직접 타이핑 가능:

<div elname="element" class="va-filterbox [size]..." tag-name="filterbox" field="true">
  <div elname="fieldWrapper" class="field-wrapper" role="combobox">
    <input elname="field" type="text" style="border:0px">   ← readonly 없음
    <div elname="focusLine" class="focus-line"></div>
    <div class="va-combobox-dropdown">▼</div>
  </div>
  <div elname="popDiv" class="menu-button-pop-div">
    <div elname="pop" class="va-menu-pop" role="listbox"
         style="position:absolute; display:none">
      <div elname="popInner" class="combobox-pop-div">
        <!-- 필터된 listItem만 표시 -->
      </div>
    </div>
  </div>
</div>

핵심 차이: va_component.js:2921의 this.fieldElement.removeAttribute('readonly') — Combobox와 달리 readonly를 명시적으로 제거해 자유 입력 활성화.


11. Filterbox 계열 형제 컴포넌트

컴포넌트역할

Va.Filterbox 표준 필터박스 (이 문서)
Va.FilterboxRaw 경량형 (기능 축소)
Va.FilterboxField Filterbox + Field 래퍼 (라벨/검증)

12. 언제 쓰나

Filterbox가 맞을 때

  • 옵션이 50개 이상 — 스크롤보다 타이핑이 빠름
  • 국가·도시·부서·제품 등 자동완성이 자연스러운 데이터
  • 사용자가 대략적인 이름만 알고 있을 때
  • 여러 필드에서 매칭 필요 (filterKeys로 이름/이메일/코드 모두)

다른 걸 쓸 때

  • 옵션이 10개 이하 → Va.Combobox (스크롤로 충분)
  • 라벨 필요 → Va.FilterboxField
  • 다중 선택 + 칩 UI → Va.Tag
  • 자유 텍스트 입력 (사전 정의 안 됨) → Va.Input
  • 서버 검색 → 별도 구현 (dataMode 활용)

13. 흔한 조합 예시

// 국가 선택 (실시간 필터, display로만 검색)
{
    tagName: 'filterbox',
    filterKeys: ['display'],
    isFilterRuntime: true,
    data: countries    // 200+개국
}

// 여러 필드 검색 (사원 조회)
{
    tagName: 'filterbox',
    filterKeys: ['name', 'employeeId', 'email'],
    isFilterRuntime: true,
    template: {
        tagName: 'listItem',
        layout: 'ds-flex fd-column',
        tags: [
            { tagName: 'div', innerHTML: '{name}' },
            { tagName: 'div', innerHTML: '{email}', style: 'color:gray; font-size:12px' }
        ]
    },
    data: employees
}

// 대량 데이터, Enter로만 (부담 방지)
{
    tagName: 'filterbox',
    filterKeys: ['name'],
    isFilterRuntime: false,  // Enter 눌러야 필터
    data: bigDataSet         // 수만 건
}

// 다중 선택 + 필터 (Combobox 다중 + 검색)
{
    tagName: 'filterbox',
    multiSelect: true,
    addCheckAll: true,
    filterKeys: ['display'],
    isFilterRuntime: true,
    data: tags
}

// 자유 입력 허용 (데이터에 없는 값도 확정)
{
    tagName: 'filterbox',
    editable: true,
    data: suggestions
}

14. 알아두면 좋을 주의사항

  1. filterKeys 필드 값이 null이면 크래시 — 소스가 item[filterKey].indexOf(...) 호출. 데이터에 null 값 방어 필요.
  2. 대소문자 구분  indexOf 사용. filterKeys를 미리 소문자로 가공하거나 필터 로직 오버라이드.
  3. 한글 초성 검색 안 됨 — 별도 라이브러리로 데이터 가공 필요.
  4. isFilterRuntime: false가 기본 — Enter 눌러야 필터. 즉각 반응 원하면 명시적으로 true.
  5. filter()는 dataManager 필터 — 원본 데이터는 유지, 표시만 좁혀짐. clearFilter()로 복원.
  6. getValue()가 값을 반환하는 로직은 Combobox와 다를 수 있음  editable: true일 때 필드 텍스트가 그대로 값으로 저장될 수 있음. 실제 확인 필요.
  7. 이벤트 이름이 filterboxItemClick — Combobox의 listItemClick이 아님.
  8. 필드가 편집 가능해서 값 상태와 표시가 불일치 가능 — 사용자가 텍스트를 지웠는데 실제 값(value)은 남아 있을 수 있음. Tab 시 자동 클리어 로직으로 일부 대응.
  9. rowHeight 기본이 30 — Combobox(34)보다 얇음. 시각적으로 정보 밀도 높음.
  10. 팝업이 hiddenArea로 이동 — 부모 stacking 영향 없음.
  11. 가상 스크롤 자동 — Combobox와 동일.
  12. 필터가 걸린 상태에서 CRUD  addData() 등 호출 시 필터 유지 여부 확인 필요. 예상과 다르면 clearFilter() 명시.
  13. 에디터 모드용 fakeData — VanillaFront Editor에서 미리보기 시 사용.