CheckboxGroupField (체크박스그룹필드)
Va.CheckboxGroupField — 라벨 + 다중 선택 체크박스 그룹
Va.CheckboxGroup이 순수 다중 선택 그룹이라면, Va.CheckboxGroupField는 그 위에 폼 라벨·필수 표시·검증 메시지를 얹은 완성 폼 필드입니다. Field 계열 아키텍처 그대로, 내부에 Va.CheckboxGroup을 소유하는 Composition 구조.
- 클래스: Va.CheckboxGroupField — va_component.js:11011
- short name: checkboxGroupField
- 상속: Va.Field (다른 Field 형제들과 같음)
- 내부 컴포넌트: Va.CheckboxGroup 인스턴스 (fieldComponent)
- isContainer: true
- 베이스 CSS: va-checkbox-group-field

1. 기본 사용
{
tagName: 'checkboxGroupField',
label: '관심 분야',
key: 'code',
display: 'name',
data: [
{ code: 'JS', name: 'JavaScript', checked: true },
{ code: 'TS', name: 'TypeScript' },
{ code: 'PY', name: 'Python' }
],
required: true,
onChange: 'onInterestsChange'
}
라벨 + 검증 + 여러 체크박스가 한 번에 세팅. 값은 선택된 key들의 배열로 다룹니다.
2. Field 계열에서의 위치
Va.Field
├─ Va.InputField ← Va.Input
├─ Va.CheckboxField ← Va.Checkbox (단일)
├─ Va.CheckboxGroupField ← Va.CheckboxGroup (다중) ← 이 문서
├─ Va.RadioField ← Va.Radio (단일)
├─ Va.RadioGroupField ← Va.RadioGroup (배타)
└─ ...
CheckboxGroupField의 정체: Field 베이스 + 내부에 Va.CheckboxGroup 인스턴스.
3. CheckboxGroup / 다른 Field와의 차이
항목Va.CheckboxGroupVa.CheckboxGroupFieldVa.CheckboxField
| 폼 라벨 | ✕ | ✓ | ✓ |
| 검증 메시지 | ✕ | ✓ | ✓ |
| info 툴팁 | ✕ | ✓ | ✓ |
| 필수 표시(별표) | ✕ | ✓ | ✓ |
| 선택 개수 | N개 (다중) | N개 (다중) | 1개 (단일) |
| 값 형태 | key 배열 | key 배열 | boolean/YN/10 |
| 데이터 배열 렌더 | ✓ | ✓ | ✕ |
| 상속 | Component | Field | Field |
한 줄 요약: "폼 안 라벨 붙은 다중 선택 체크박스 그룹."
4. 주요 속성
데이터 관련 (CheckboxGroup 계승)
속성설명
| data | 옵션 배열. 각 항목 { [key], [display], checked } |
| key | 값 필드명 (예: 'code') |
| display | 표시 필드명 (예: 'name') |
| direction | 'horizontal'(기본) / 'vertical' |
| checkboxLabelClick | 라벨 클릭 토글 (기본 true) |
| readonly / disabled | 상태 (자식 전체에 전파) |
라벨 관련 (Field 상속)
속성설명
| label | 폼 라벨 |
| labelPosition | top / bottom / left / right |
| labelWidth | 라벨 폭 |
| noLabel | 폼 라벨 숨김 |
| infoButton | info 아이콘 |
| required | 필수 표시 |
검증
속성설명
| validation | {state, size, message} |
| validationState | success / warning / error |
| validationMessage | 메시지 |
세부 커스터마이즈 (checkboxGroup 옵션 키)
{
tagName: 'checkboxGroupField',
label: '카테고리',
checkboxGroup: { // ← 내부 CheckboxGroup에 직접 전달
stopPropagation: false
}
}
각 Field 계열 옵션 키:
- InputField → input
- CheckboxField → checkbox
- CheckboxGroupField → checkboxGroup
- RadioGroupField → radioGroup
5. 이벤트
이벤트시그니처발생 시점
| change | (component, element, key, evt) | 자식 체크박스 상태 변경 시. key는 변경된 항목의 key (전체 배열이 아님) |
⚠️ change 인자 주의 — CheckboxGroup과 동일하게, 세 번째 인자는 변경된 항목의 key 하나. 전체 선택 상태는 comp.getValue() 재호출로.
onInterestsChange(comp, el, key, evt) {
console.log('바뀐 항목:', key); // 'JS'
console.log('전체 선택:', comp.getValue()); // ['JS', 'TS']
}
이벤트 목록이 매우 짧음 — 소스에 this.events = ['change']만 있습니다. focus/blur 등 표준 Field 이벤트가 재발화 코드에 포함되지 않아, 필요하면 component.fieldComponent에 직접 리스너를 붙여야 합니다.
6. 메서드
값 조회·세팅 (CheckboxGroup 위임)
메서드설명
| getValue() | 체크된 항목의 key 배열 반환 |
| setValue(value) | key 배열 넘기면 매칭되는 항목만 체크 |
| getDisplay() | 체크된 항목의 display 배열 |
| getDisplayAsText() | display 배열을 콤마로 이은 문자열 |
데이터 관리
메서드설명
| setData(data) | 데이터 전체 교체 |
| getData() | 현재 데이터 반환 |
| addData(item) | 항목 추가 (기본 체크됨) |
| insertData(item, index) | 특정 위치에 삽입 |
상태
메서드설명
| setDisabled(bool) | 자식 전체 비활성화 |
| setReadOnly(bool) | 자식 전체 읽기 전용 |
자식 추가
메서드설명
| append(component) | 프로그램적으로 체크박스 자식 추가 |
주의: getChecked(), setChecked() 같은 단일 체크박스용 메서드는 없음. CheckboxField와 달리 다중 그룹이라 값은 배열 단위로만 다룹니다.
7. 내부 구조
<div elname="element" class="va-field va-checkbox-group-field [vertical|horizontal]"
field="true">
<div elname="inner" class="field-inner">
<div elname="labelDiv" class="label-div">
<label cpname="label">관심 분야 <span class="required">*</span></label>
</div>
<div elname="comment" class="field-comment"></div>
<div elname="fieldDiv" class="field-div">
<div cpname="field" class="va-checkbox-group [horizontal|vertical]">
← 내부 Va.CheckboxGroup
<div class="checkbox-group-inner">
<div class="va-checkbox">…</div>
<div class="va-checkbox">…</div>
<!-- 자식 체크박스들 -->
</div>
</div>
</div>
</div>
<div elname="validationDiv" style="display:none">
<div class="va-validation">...</div>
</div>
</div>
폼 라벨 방향과 체크박스 배치 방향 두 축이 각각 존재:
- labelPosition — 폼 라벨의 위치 (Field 담당)
- direction — 그룹 안 체크박스 배열 방향 (CheckboxGroup 담당)
두 옵션을 따로 조합할 수 있습니다.
8. update()의 특별한 동작 — 200ms 지연
update()에서 상태 반영이 _setTimer('update', ..., 200)으로 감싸져 있어 200ms 후에 실행됩니다 (va_component.js:11058-11064).
this._setTimer('update', ()=>{
this.fieldComponent.setReadOnly(this.readonly);
this.fieldComponent.setDisabled(this.disabled);
...
}, 200)
이유는 자식 체크박스가 렌더되기를 기다리는 것으로 보입니다. 실무적 함의:
- setReadOnly() / setDisabled() 호출 후 즉시 UI에 반영되지 않을 수 있음 (200ms 후 반영)
- 연속 호출 시 마지막 것만 반영됨 (_setTimer 특성)
프로그램적으로 상태 바꾸고 바로 다른 로직 진행할 때 이 지연을 인지하고 있어야 합니다.
9. 언제 쓰나
CheckboxGroupField가 맞을 때
- 폼 안 다중 선택 필드 (관심 분야, 선호 카테고리, 필터 조건)
- 라벨·검증·필수 표시가 필요할 때
- 서버에서 받은 동적 옵션 목록
- 항목 5개 이상 유동적
다른 걸 쓸 때
- 라벨 없이 인라인 → Va.CheckboxGroup
- 단일 체크박스 (동의) → Va.CheckboxField
- 하나만 선택 (배타) → Va.RadioGroupField
- 옵션 20개 이상 (드롭다운) → Va.ComboboxField + multiSelect
- 칩(태그) 형태로 표시 → Va.TagField
10. 흔한 조합 예시
// 표준
{
tagName: 'checkboxGroupField',
label: '관심 분야',
key: 'code',
display: 'name',
data: [
{ code: 'JS', name: 'JavaScript' },
{ code: 'TS', name: 'TypeScript' },
{ code: 'PY', name: 'Python' }
],
required: true,
onChange: 'onChange'
}
// 세로 배치
{
tagName: 'checkboxGroupField',
label: '알림 설정',
key: 'code',
display: 'name',
direction: 'vertical',
data: [
{ code: 'EMAIL', name: '이메일', checked: true },
{ code: 'SMS', name: 'SMS' },
{ code: 'PUSH', name: '푸시 알림', checked: true }
]
}
// 좌측 라벨 (폼 정렬)
{
tagName: 'checkboxGroupField',
label: '요일',
labelPosition: 'left',
labelWidth: 100,
key: 'code',
display: 'name',
data: [
{ code: 'MON', name: '월' },
{ code: 'TUE', name: '화' },
{ code: 'WED', name: '수' },
{ code: 'THU', name: '목' },
{ code: 'FRI', name: '금' }
]
}
// info 툴팁
{
tagName: 'checkboxGroupField',
label: '수신 채널',
infoButton: {
tooltip: '2개 이상 선택 권장'
},
key: 'code',
display: 'name',
data: [ ... ]
}
// 서버에서 데이터 로드
mounted() {
CategoryService.list(this, {}, (view, ok, res) => {
if (ok) view.getRef('cats').setData(res.data.list);
});
}
// 초기값 프로그램적 세팅
this.getRef('cats').setValue(['JS', 'PY']);
11. 실전 예 — 알림 설정 폼
class NotificationSettings extends Va.View {
async mounted() {
// 사용자의 기존 설정 로드
const res = await NotifService.getUserSettings(this);
if (res.result) {
// 전체 채널 옵션 + 이 사용자의 선택
const all = [
{ code: 'EMAIL', name: '이메일' },
{ code: 'SMS', name: 'SMS' },
{ code: 'PUSH', name: '푸시 알림' },
{ code: 'KAKAO', name: '카카오톡' }
];
const selected = res.data.channels; // ['EMAIL', 'PUSH']
// 체크 상태 매핑
const data = all.map(c => ({
...c,
checked: selected.includes(c.code)
}));
this.getRef('channels').setData(data);
}
}
onSave(btn, el, evt) {
const channels = this.getRef('channels').getValue();
if (channels.length === 0) {
this.getRef('channels').setValidation('error', '최소 1개 채널을 선택하세요');
return;
}
this.getRef('channels').clearValidation();
NotifService.save(this, { channels }, (view, ok) => {
if (ok) new Va.Alert({ title: '완료', message: '저장되었습니다' }).show(view);
});
}
config() {
return {
tagName: 'page',
tags: [{
tagName: 'panel',
tags: [
{ tagName: 'h2', innerHTML: '알림 채널 설정' },
{
tagName: 'checkboxGroupField',
ref: 'channels',
label: '수신 채널',
key: 'code',
display: 'name',
direction: 'vertical',
required: true,
infoButton: {
tooltip: '알림을 받을 채널을 모두 선택하세요'
}
},
{
tagName: 'button',
text: '저장',
appearance: 'primary',
onClick: 'onSave'
}
]
}]
};
}
}
12. 알아두면 좋을 주의사항
- getValue() 반환은 key 배열 — 서버 전송 시 배열로 처리.
- setValue()도 배열 전달 — 단일 값도 배열로 감쌈.
- change 인자는 변경된 항목의 key — 전체 상태 아님. 전체는 getValue().
- 이벤트 목록이 ['change']만 있음 — focus/blur 등 다른 Field 표준 이벤트는 재발화 안 됨. 필요하면 fieldComponent에 직접.
- update()가 200ms 지연 — setReadOnly/setDisabled 즉시 반영 안 됨.
- addData는 새 항목이 자동으로 체크됨 — 미체크로 추가하려면 데이터 조작 후 setData().
- removeData/modifyData 없음 — 전체 교체는 setData().
- 검증 자동 리셋 없음 — CheckboxField는 keydown/select 시 자동 리셋, 그룹은 그런 로직 없음. change 후 명시적으로 clearValidation() 호출 필요할 수 있음.
- key/display 필드명 유연 — 데이터 형태에 맞춰 자유롭게 (code/name, id/label 등).
- direction은 CSS 클래스로 반영 — 실제 flex 방향은 프레임워크 CSS에서.
- 폼 라벨과 그룹 방향 독립 — labelPosition: 'left' + direction: 'vertical' 조합 가능.
- focus() 편의 메서드 없음 — CheckboxGroup에도 없고 Field에도 위임 명시 없음. 프로그램적 포커스가 필요하면 component.fieldComponent.getChildComponents()[0].focus() 우회.
13. checkboxGroupField vs radioGroupField vs comboboxField(multi) 선택
상황추천
| 여러 옵션 중 여러 개 선택 | checkboxGroupField |
| 여러 옵션 중 하나만 | radioGroupField |
| 옵션 5개 이하, 가로 배치 | checkboxGroupField direction: 'horizontal' |
| 옵션 5개 이상, 세로 배치 | checkboxGroupField direction: 'vertical' |
| 옵션 20개 이상 | comboboxField + multiSelect: true (드롭다운) |
| 선택된 것을 칩으로 표시 | tagField |
| 트리 구조 그룹 | 커스텀 (기본 지원 안 됨) |