DropDownTextList
Tom Select 2.6.2 기반 검색·조건 태그 컨트롤입니다. 키·표시값을 검색하고 그룹별 후보를 선택합니다. 태그를 클릭하면 AND/OR와 비교 연산자를 편집합니다.
<syn_dropdowntextlist id="animals" syn-datafield="Conditions"
syn-events="['initialize','change']"
syn-options="{
optgroups:[{value:'mammal',label:'Mammal'},{value:'bird',label:'Bird'}],
optgroupField:'class',valueField:'value',labelField:'name'
}"></syn_dropdowntextlist>
const control = syn.uicontrols.$dropdowntextlist;
control.setValue('animals', [
{class:'mammal',value:'dog',name:'Dog'},
{class:'mammal',value:'cat',name:'Cat'},
{class:'bird',value:'duck',name:'Duck'}
]);
control.addItem('animals', 'dog');
const saved = control.getValue('animals');
// [{groupID:'mammal',logic:'AND',operator:'eq',key:'dog',value:'Dog'}]
control.clear('animals');
control.setValue('animals', saved);
반환값과 식별
선택 태그는 기본적으로(groupDisplay:'tooltip') 항목 이름만 보여주고, 그룹 이름(optgroups.label, 그룹이 등록되지 않았다면 그룹 ID, 그룹 ID도 비어 있으면 기타)은 태그에 마우스를 올렸을 때의 툴팁(title)과 접근성 이름으로 제공합니다. groupDisplay:'inline'을 지정하면 편집 버튼 왼쪽에 그룹 이름을 함께 표시하고, groupDisplay:'badge'를 지정하면(hideLogicBadge:false일 때만) AND/OR 배지 뒤에 그룹 이름을 이어서 보여줍니다(AND · 직원 명, 일반 텍스트의 key 표시와 같은 방식이며 길면 그룹 이름 부분만 줄임표로 자르고 그룹 ID가 비어 있는 후보는 AND/OR만 표시). range 그룹의 범위 태그는 groupDisplay 값과 관계없이 항상 값만 보여주고 그룹 이름은 툴팁으로 제공합니다. 그룹 이름(inline일 때)과 편집 버튼은 클릭 또는 Enter/Space/F2로 같은 태그를 선택하고 편집창에 포커스를 이동합니다. 편집창은 선택한 태그 아래에 표시하며 화면 아래 공간이 부족하면 위로 이동하고, 오른쪽 경계를 벗어나지 않도록 조정합니다. 스크롤·창 크기 변경 시 위치를 다시 계산합니다. 취소·Escape·적용 후에는 해당 태그의 편집 버튼으로 포커스를 돌려줍니다. 적용·취소 버튼은 Tabler btn-group(적용은 btn btn-primary, 취소는 btn)이며 높이는 콤보박스와 같은 34px입니다.
hideLogicBadge:false이면 AND/OR를 왼쪽 상단 배지로 보여주고(기본값 true는 배지를 만들지 않아 AND/OR는 툴팁과 편집창으로만 확인), 비교 조건은 왼쪽 테두리로 구분합니다. 배지를 숨기면 컨테이너에 dttl-hide-badge 클래스가 붙어 배지가 튀어나올 자리로 둔 태그 위쪽 여백(margin-top)이 0이 되고 줄 간격(row-gap)이 5px로 줄어듭니다. 이 설정은 초기화 때 한 번만 반영합니다. 편집창의 연결·비교 선택값과 목록 항목도 같은 Tabler 색상을 사용하며 글자색은 흰색입니다. 전체 조건은 태그에 마우스를 올리거나 편집 버튼의 접근성 이름으로 확인할 수 있습니다.
| 구분 | 값 | Tabler 색상 |
|---|---|---|
| 연결 | AND / OR | blue / red |
| 비교 | 같음 (eq) | blue |
| 비교 | 작게 (lt) | green |
| 비교 | 같거나작게 (lte) | cyan |
| 비교 | 크게 (gt) | pink |
| 비교 | 같거나크게 (gte) | orange |
| 비교 | 다름 (neq) | red |
| 비교 | 시작함 (begins_with) | gray-600 (회색) |
| 비교 | 끝남 (ends_with) | purple |
| 비교 | 포함 (contains) | teal |
| 비교 | 미포함 (not_contains) | indigo |
색상은 컨트롤 CSS의 data-dttl-logic·data-dttl-operator 규칙 에서 공통 관리하며 --tblr-* 변수를 사용합니다. 그룹 추가·제거 시 선택 태그의 그룹 표시도 갱신합니다.
getValue()는 선택 순서의 새 객체 배열을 반환하며 빈 선택은 []입니다. maxItems:1이어도 배열입니다.
| 필드 | 의미 |
|---|---|
groupID | optgroupField 속성값. 생략된 후보 그룹은 빈 문자열 |
logic | AND 또는 OR. setValue에서 생략하면 AND |
operator | eq, lt, lte, gt, gte, neq, begins_with, ends_with, contains, not_contains. setValue에서 생략하면 contains |
key | valueField 속성값 |
value | labelField 속성값. 사용자가 별도로 입력하는 비교값이 아님 |
연산자는 각각 같음, 작게, 같거나작게, 크게, 같거나크게, 다름, 시작함, 끝남, 포함, 미포함입니다. 컨트롤은 조건을 수집하며 조건 평가나 SQL 생성은 수행하지 않습니다.
그룹·키는 대소문자를 구분하는 문자열로 정규화합니다. 같은 그룹·키는 한 번만 선택할 수 있습니다. 다른 그룹에 같은 키가 있으면 addItem({groupID:'mammal',key:'dog'})처럼 참조 객체를 전달해야 합니다. 모호한 문자열 키는 오류입니다. DOM을 반환하는 메서드는 실제 HTMLElement를 반환합니다.
setValue 구분
| 입력 | 동작 |
|---|---|
| 후보 객체 배열 | 후보 목록 교체. 남아 있는 그룹·키의 선택 조건 유지 및 표시값 갱신. 사라진 후보 선택 해제 |
{groupID,logic,operator,key,value} 배열 | 전체 선택 복원. 없는 후보는 등록하고 중복 조건은 첫 항목만 선택 |
| 문자열 또는 문자열 배열 | 기존 후보의 키로 선택 재설정. 알 수 없는 키는 오류 |
[] | 선택만 해제. 후보는 유지 |
혼합 배열이나 잘못된 조건은 변경 전에 오류를 발생시킵니다. 조건 객체는 groupID, key가 필요하고 value는 후보가 없을 때 표시값으로 사용하며, logic과 operator를 생략하면 AND, contains를 적용합니다. 후보 스키마의 optgroupField가 groupID이거나 valueField가 key이면 후보와 조건 객체를 구분할 수 없으므로 이때는 logic 또는 operator가 있는 객체만 조건으로 보고, 생략하려면 addOptions()로 후보를 공급한 뒤 addItem()을 사용합니다.
silent:true는 컨트롤 change 및 기반 select의 change 이벤트를 억제합니다. item_add, item_remove, clear 등 개별 이벤트는 발생할 수 있습니다. 변경이 없는 선택 재설정은 change를 발생시키지 않습니다. HandStack 거래 setter가 전달하는 세 번째 인자의 메타데이터 객체는 silent로 처리하지 않습니다.
메서드
모듈 호출은 syn.uicontrols.$dropdowntextlist.method(elID, ...args)입니다. getControl(elID)로 받은 인스턴스에서는 elID 없이 호출합니다.
| 메서드 | 동작 |
|---|---|
addOption(data,user_created=false), addOptions(data[],user_created=false) | 후보 추가. 동일 그룹·키는 유지하며 드롭다운은 자동 갱신하지 않음 |
updateOption(ref,data) | 후보와 선택 태그 갱신. 그룹·키 변경 시 기존 후보와 충돌하면 오류 |
removeOption(ref) | 후보와 해당 선택 제거 |
getOption(ref,create=false) | 후보 DOM 반환. 필요 시 렌더링 |
getAdjacent(element,direction) | 이전(-1)/다음(1) 후보 DOM |
refreshOptions(triggerDropdown) | 검색 목록 갱신 |
clearOptions(clearFilter?) | 선택하지 않은 후보 제거. 콜백이 true인 후보와 선택된 후보는 유지 |
clearFilter(option,ref) | 기본 유지 판단: 현재 선택된 후보이면 true |
clear(silent) | 선택 전체 해제 |
getItem(ref) | 선택 태그 DOM |
addItem(ref|text,silent) | 캐럿 위치에 선택 추가. 후보에 없는 문자열은 create:true일 때 일반 텍스트로 추가 |
removeItem(ref|HTMLElement,silent) | 선택 해제 |
createItem(value,callback?) | create 설정으로 선택. 후보의 키·표시값과 같으면 그 후보, 아니면 일반 텍스트 생성 |
refreshItems() | 선택 태그 다시 렌더링 |
addOptionGroup(id,data), removeOptionGroup(id), clearOptionGroups() | 그룹 추가·제거. 그룹 제거 자체는 후보를 삭제하지 않음 |
on(event,handler), off(event,handler?), trigger(event,...args) | 이벤트 구독·해제·실행 |
open(), close(), positionDropdown() | 드롭다운 열기·닫기·위치 갱신 |
focus(), blur() | 입력 포커스 이동 |
lock(), unlock() | 포커스 가능한 입력 잠금·해제. 태그 편집·삭제도 잠금 |
disable(), enable() | 포커스를 포함한 사용자 조작 비활성화·활성화 |
getValue(), setValue(value,silent) | 후보 조건 조회·데이터 공급·선택 복원. 일반 텍스트는 제외 |
getGroupConditions(list) | [{operator,value,logic}] 목록을 operator와 logic이 같은 것끼리 묶어 [{name,args,logic}]로 반환하는 정적 함수(컨트롤 인스턴스에는 없음). 아래 "조건 묶음 변환" 절 참고 |
getSummaryText(options?) | 선택한 조건을 사용자에게 보여줄 텍스트로 반환. 아래 "조건 요약 텍스트" 절 참고 |
getNormalText(), setNormalText(items,silent) | 일반 텍스트 [{logic,operator,key,value}] 조회·교체. 아래 "일반 텍스트" 절 참고 |
setRange(groupID,start,end), getRange(groupID) | range 그룹의 시작·끝 범위 설정·조회. 아래 "범위 입력" 절 참고 |
setCaret(index), isFull() | 캐럿 이동·선택 한도 도달 여부 |
clearCache(), setTextboxValue(str) | 렌더링 캐시 초기화·검색 문자열 설정 |
load(query) | load 콜백 호출. 최신 요청만 반영 |
sync() | source select의 후보·선택을 읽고 기존 조건 메타데이터 유지 |
destroy() | 이벤트·팝오버·DOM·컨트롤 레지스트리 정리. 같은 요소 재초기화 가능 |
ref는 문자열 키 또는 {groupID,key}입니다. clearOptions 콜백 인자는 원래 후보 데이터와 ref입니다. persist:false이면 user_created 후보는 선택 해제 시 제거됩니다(일반 텍스트는 설정과 관계없이 제거). getControl().source는 내부 기반 select이며 option의 value는 JSON.stringify([groupID,key]), text는 표시값입니다. 외부에서 이 select를 수정한 후 sync()를 호출할 수 있습니다. 화면의 syn-datafield 값은 공개 getValue/setValue를 사용합니다.
이벤트
초기화 전에 onInitialize, onChange 등 Tom Select 이름의 콜백 옵션을 제공하거나 syn-events와 페이지 event.<elID>_<event>를 사용합니다. 초기화 후에는 인스턴스 on을 사용합니다. 핸들러의 this는 컨트롤 인스턴스입니다.
| 이벤트 | 인자 |
|---|---|
initialize, focus, blur, clear, option_clear, optgroup_clear, destroy | 없음 |
change | 조건 객체 배열, 일반 텍스트 객체 배열(getValue(), getNormalText()). 논리·연산자 편집도 포함 |
item_add, item_remove | 선택한 항목 하나 {groupID,logic,operator,key,value}(일반 텍스트는 {normal:true,logic,operator,key,value}), 태그 HTMLElement. 조건이 지정되지 않은 항목은 logic:'AND', operator:'contains'로 전달 |
item_select | 태그 HTMLElement |
option_add | {groupID,key}, 원래 후보 데이터(일반 텍스트는 {normal:true,logic,operator,key,value} 두 인자 모두) |
option_remove | {groupID,key}(일반 텍스트는 {normal:true,logic,operator,key,value}) |
option_change | 조건 편집창의 적용으로 논리·연산자가 바뀐 항목 하나 {groupID,logic,operator,key,value}(일반 텍스트는 {normal:true,logic,operator,key,value}), 변경 전 {logic,operator}. change 다음에 호출. 범위 편집창의 변경에는 발생하지 않음 |
optgroup_add | id, 그룹 데이터 |
optgroup_remove | id |
dropdown_open, dropdown_close | 드롭다운 HTMLElement |
type | 검색 문자열 |
load | 원래 후보 데이터 배열 |
페이지 핸들러와 DOM 이벤트의 중복 호출을 막기 위해 컨트롤 이벤트는 초기화 시 직접 연결합니다. destroy에서 원래 syn-events를 복원합니다.
옵션과 비동기 제공자
드롭다운 크기는 입력 영역의 width와 별도로 설정합니다.
| 옵션 | 기본값 | 설정값 |
|---|---|---|
dropdownWidth | '100%': 컨트롤 폭 | 'auto': 현재 표시 목록·그룹 제목에 맞춤, 숫자 또는 '320px': 고정 너비 |
dropdownHeight | 'auto': 내용에 맞춤, 목록 영역 최대 200px | 숫자 또는 '180px': 드롭다운 전체의 고정 높이 |
숫자는 양수 픽셀값입니다. 기본 너비는 컨트롤 폭('100%')이며, 기본 높이는 기존 Tom Select의 크기 스타일을 유지합니다. dropdownWidth:'auto'는 검색·후보 갱신·비동기 조회·창 크기 변경 시 다시 계산하며 화면 오른쪽을 넘지 않도록 제한합니다. 고정 높이에서 내용이 넘치면 목록 내부를 스크롤합니다. null도 해당 옵션의 기본값으로 처리합니다. 후보 목록을 세로로 스크롤하면 현재 그룹의 헤더(.optgroup-header)가 목록 상단에 고정되고 다음 그룹의 헤더가 올라오면 밀려납니다. 목록에 그려진 그룹이 둘 이상이면 목록 위쪽에 그룹 이름 버튼 줄(div.dttl-group-nav, Tabler btn-group)이 나타나고, 버튼을 누르면 해당 그룹의 헤더가 상단에 오도록 부드럽게 스크롤합니다. 버튼을 눌러도 입력 포커스는 유지되며(tabindex="-1") 목록을 스크롤하면 상단에 닿은 그룹의 버튼이 활성(active)으로 표시됩니다. 검색으로 그룹이 바뀌면 버튼도 다시 만들고, 그룹이 하나뿐이거나 후보가 없는 그룹(범위 그룹)은 버튼에 포함하지 않습니다. 버튼이 많으면 가로로 스크롤하며 dropdownHeight를 고정했을 때는 버튼 줄 높이만큼 목록 높이를 줄입니다. groupNav:false이면 버튼 줄을 만들지 않습니다. 운영체제의 "동작 줄이기" 설정이면 즉시 이동합니다.
<!-- 기본값: 컨트롤 폭, 기존 높이 -->
<syn_dropdowntextlist id="defaultSize" syn-options="{}"></syn_dropdowntextlist>
<!-- 목록에 맞춘 너비, 기본 높이 -->
<syn_dropdowntextlist id="autoSize" syn-options="{dropdownWidth:'auto'}"></syn_dropdowntextlist>
<!-- 드롭다운 전체 크기 고정 -->
<syn_dropdowntextlist id="fixedSize" syn-options="{dropdownWidth:320,dropdownHeight:180}"></syn_dropdowntextlist>
기본값은 maxItems:null, hideSelected:true, clearAfterSelect:true, create:false, persist:true, groupDisplay:'tooltip'('tooltip': 그룹 이름을 툴팁으로, 'inline': 태그 안에 표시, 'badge': AND/OR 배지 뒤에 표시, 배지를 표시할 때만 동작), hideLogicBadge:true(false이면 태그 왼쪽 위에 AND/OR 배지를 표시), groupNav:true(그룹 이동 버튼, 아래 설명), loadThrottle:200, preload:false입니다. create:true로 만든 항목은 그룹 없이 일반 텍스트가 되며 defaultGroupID는 더 이상 사용하지 않습니다. 자세한 규칙은 "일반 텍스트" 절을 참고합니다.
함수 옵션은 페이지 hook.controlInit 또는 controlLoad에서 제공합니다.
syn.uicontrols.$dropdowntextlist.controlLoad('animals', {
create(input, callback) {
callback({class:'custom',value:input,name:input});
},
load(query, callback) {
// applicationSearch는 애플리케이션에서 구현하는 데이터 제공자입니다.
applicationSearch(query).then(callback).catch(() => callback([]));
}
});
create는 객체 반환, callback 또는 Promise를 지원하며 결과는 일반 텍스트(valueField는 key, labelField는 value, 그룹은 무시)가 됩니다. load는 후보 배열 반환, callback 또는 Promise를 지원하며 callback의 두 번째 인자로 그룹 배열을 전달할 수 있습니다. callback 방식은 완료 시 한 번 호출하고 데이터를 직접 반환하지 않습니다. 예외·Promise 거절은 잠금/로딩 상태를 해제하고 콘솔에 기록합니다. callback 방식은 실패 시에도 callback()을 호출해야 합니다. 데이터 교체·초기화·파괴 이후 오래된 응답과 이전 검색 응답은 무시합니다.
일반 텍스트 (options에 없는 입력)
create:true