컴포넌트/필드 컴포넌트

CheckboxGroup (체크박스그룹)

VanillaFront 2026. 9. 12. 19:29

Va.CheckboxGroup — 여러 체크박스를 데이터로 관리하는 그룹

여러 개의 선택지 중 여러 개를 동시 선택할 수 있는 컴포넌트. 각 체크박스를 하드코딩으로 나열하지 않고, 데이터 배열로 선언해 한 번에 렌더링합니다. 값은 선택된 key들의 배열로 다룹니다.

  • 클래스: Va.CheckboxGroup — va_component.js:10813
  • short name: checkboxGroup
  • 상속: Va.Component (PureField 아님!)
  • isContainer: true
  • 베이스 CSS: va-checkbox-group


1. 기본 사용

{
    tagName: 'checkboxGroup',
    key: 'code',
    display: 'name',
    data: [
        { code: 'A', name: '항목 A', checked: true },
        { code: 'B', name: '항목 B', checked: false },
        { code: 'C', name: '항목 C', checked: true }
    ],
    onChange: 'onSelectionChange'
}

getValue() 결과: ['A', 'C'] — 체크된 항목의 key 배열.


2. Va.Checkbox를 나열하는 것과의 차이

여러 체크박스가 필요할 때 두 가지 접근이 있습니다.

✕ 하드코딩 나열

{
    tagName: 'div',
    tags: [
        { tagName: 'checkbox', checkboxLabel: '항목 A', ref: 'chkA' },
        { tagName: 'checkbox', checkboxLabel: '항목 B', ref: 'chkB' },
        { tagName: 'checkbox', checkboxLabel: '항목 C', ref: 'chkC' }
    ]
}
  • 항목이 늘어나면 코드 반복
  • 값 조회할 때 getRef('chkA').getChecked() 반복
  • 서버에서 받은 동적 목록에 대응 못함

✓ CheckboxGroup

{
    tagName: 'checkboxGroup',
    key: 'code',
    display: 'name',
    data: [ ... ]   // 배열 하나로 끝
}
  • 데이터 배열 하나로 선언
  • getValue() 한 번에 선택 결과 배열 획득
  • 서버 응답을 그대로 setData() 로 넘기면 됨

3. CheckboxGroup vs Checkbox vs 다른 그룹

항목Va.CheckboxVa.CheckboxGroupVa.RadioGroup

선택 개수 1개 (단일) N개 (다중) 1개 (배타)
데이터 배열로 렌더 ✕ ✓ ✓
값 형태 boolean/YN/10 key 배열 단일 key
상속 PureField Component Component
getValue() 반환 체크 상태 선택된 key 배열 선택된 key
CRUD 메서드 없음 addData/insertData 유사
라벨 검증 ✕ ✕ ✕

한 줄 요약: "옵션 배열에서 여러 개 선택 → 결과를 key 배열로 받는 컴포넌트."


4. 주요 속성

데이터 관련

속성기본값설명

data — 옵션 배열. 각 항목은 { key값, display값, checked } 형태
key — 값으로 저장할 필드명 (예: 'code')
display — 표시할 필드명 (예: 'name')
fakeData — 에디터 모드용 미리보기 데이터

배치·상태

속성기본값설명

direction 'horizontal' 'horizontal'(가로) / 'vertical'(세로)
readonly — 읽기 전용 (모든 자식 체크박스에 전파)
disabled — 비활성화 (모든 자식에 전파)
size — 크기
checkboxLabelClick — 라벨 클릭으로 토글 (기본 true)
stopPropagation true 이벤트 버블링 차단

5. 데이터 스키마

setData()가 받는 배열의 각 항목은 이런 필드를 가질 수 있습니다:

[
    {
        code: 'A',           // key 필드 (옵션의 'key'로 지정한 이름)
        name: '항목 A',       // display 필드 (옵션의 'display'로 지정한 이름)
        checked: true,       // 초기 체크 상태 (생략 가능)
        name: '...',         // ⚠️ name 속성이 있으면 HTML name 그룹핑
    }
]

⚠️ name 필드 오버로딩 주의 — 코드상 item.name이 없으면 componentId로 자동 세팅됩니다 (va_component.js:10875-10877). 데이터의 name 필드가 사용자 이름 같은 걸 담고 있으면 HTML name 속성과 충돌할 수 있어요. 데이터 필드명을 label, title 등으로 바꾸는 게 안전.


6. 이벤트

이벤트시그니처발생 시점

change (component, element, key, evt) 자식 체크박스 상태 변경 시. key는 변경된 항목의 키 (전체 선택 배열이 아님!)
checkboxClick — 자식 체크박스 클릭 시 (실질 로직은 별도 확인 필요)
mousedown (component, element, evt) 그룹 마우스다운

change 콜백 예시

onSelectionChange(comp, el, key, evt) {
    console.log('바뀐 항목:', key);            // 예: 'B'
    console.log('현재 전체 선택:', comp.getValue());  // 예: ['A', 'C']
}

⚠️ change의 세 번째 인자가 "변경된 항목의 key" — 전체 선택 상태 배열이 아닙니다. 전체를 알려면 comp.getValue() 재호출.


7. 메서드

값 조회·세팅

메서드설명

getValue() 체크된 항목의 key 배열 반환 (예: ['A', 'C'])
getDisplay() 체크된 항목의 display 배열 반환 (예: ['항목 A', '항목 C'])
getDisplayAsText() display를 콤마로 이은 한 줄 문자열 (예: '항목 A, 항목 C')
setValue(values) key 배열을 넘기면 그에 맞춰 체크. 단일 값 넘기면 배열로 감쌈

데이터 관리

메서드설명

setData(data) 데이터 전체 교체. 기존 체크박스 모두 제거 후 재렌더
getData() 현재 데이터 반환
addData(item) 항목 하나 추가 (기본 체크됨)
insertData(item, index) 특정 위치에 삽입

상태

메서드설명

setDisabled(bool) 자식 전체 비활성화
setReadOnly(bool) / setReadonly(bool) 자식 전체 읽기 전용

⚠️ removeData나 modifyData는 없음 — CRUD 완비형이 아니라 add/insert만 지원. 전체 교체가 필요하면 setData() 사용.


8. 내부 구조

<div elname="element" class="va-checkbox-group [horizontal|vertical]" field="true">
  <div elname="inner" class="checkbox-group-inner">
    <!-- 자식 체크박스들 -->
    <div class="va-checkbox">
      <div class="checkbox-inner">
        <div class="field-wrapper"><input type="checkbox"><span>☑</span></div>
        <label>항목 A</label>
      </div>
    </div>
    <div class="va-checkbox">
      <div class="checkbox-inner">
        <div class="field-wrapper"><input type="checkbox"><span>☐</span></div>
        <label>항목 B</label>
      </div>
    </div>
    <!-- ... -->
  </div>
</div>
  • direction: 'horizontal' — 자식들이 가로 나열 (flex row)
  • direction: 'vertical' — 자식들이 세로 나열 (flex column)
  • CSS 클래스: .va-checkbox-group.horizontal / .va-checkbox-group.vertical

9. 언제 쓰나

CheckboxGroup이 맞을 때

  • 여러 옵션 중 여러 개 선택 (관심 분야, 선호 태그, 필터 조건)
  • 동적 목록 (서버에서 받은 카테고리 등)
  • 항목 수가 5개 이상이거나 유동적
  • 최종 값이 선택된 것들의 배열로 정리되면 편한 상황

다른 걸 쓸 때

  • 단일 체크박스 (동의) → Va.Checkbox / Va.CheckboxField
  • 여러 옵션 중 하나만 선택 → Va.RadioGroup
  • 드롭다운 선택 (많은 옵션) → Va.Combobox + multiSelect
  • 태그처럼 표시하며 선택 → Va.Tag
  • 라벨·검증 필요 → Va.CheckboxGroupField

10. 흔한 조합 예시

// 표준 (초기 일부 체크됨)
{
    tagName: 'checkboxGroup',
    key: 'code',
    display: 'name',
    data: [
        { code: 'JS',  name: 'JavaScript', checked: true },
        { code: 'TS',  name: 'TypeScript' },
        { code: 'PY',  name: 'Python',    checked: true },
        { code: 'GO',  name: 'Go' }
    ],
    direction: 'horizontal'
}

// 세로 배치
{
    tagName: 'checkboxGroup',
    key: 'code',
    display: 'name',
    data: [ ... ],
    direction: 'vertical'
}

// 서버 응답을 그대로 setData
mounted() {
    CategoryService.list(this, {}, (view, ok, res) => {
        if (ok) view.getRef('cats').setData(res.data.list);
    });
}

// 초기값 프로그램적 세팅
mounted() {
    this.getRef('cats').setValue(['A', 'C']);   // A와 C만 체크
}

// 읽기 전용 (표시만)
{
    tagName: 'checkboxGroup',
    key: 'code',
    display: 'name',
    data: [ ... ],
    readonly: true
}

11. 실전 예 — 관심 분야 선택

class Profile extends Va.View {
    async mounted() {
        // 서버에서 카테고리 목록 + 이 사용자의 기존 선택 로드
        const categories = await CategoryService.list(this);
        const my         = await ProfileService.getInterests(this);

        // 카테고리에 사용자 선택 상태 매핑
        const data = categories.data.list.map(c => ({
            code: c.code,
            name: c.name,
            checked: my.data.interests.includes(c.code)
        }));

        this.getRef('interests').setData(data);
    }

    onSave(btn, el, evt) {
        const selected = this.getRef('interests').getValue();
        if (selected.length === 0) {
            new Va.Alert({ title: '알림', message: '최소 1개 선택하세요' }).show(this);
            return;
        }

        ProfileService.save(this, { interests: selected }, this.onSaved);
    }

    onSaved(view, ok) {
        if (ok) new Va.Alert({ title: '저장', message: '저장 완료' }).show(view);
    }

    config() {
        return {
            tagName: 'page',
            tags: [{
                tagName: 'panel',
                tags: [
                    { tagName: 'h2', innerHTML: '관심 분야' },
                    {
                        tagName: 'checkboxGroup',
                        ref: 'interests',
                        key: 'code',
                        display: 'name',
                        direction: 'horizontal'
                    },
                    {
                        tagName: 'button',
                        text: '저장',
                        appearance: 'primary',
                        onClick: 'onSave'
                    }
                ]
            }]
        };
    }
}

흐름:

  1. 서버에서 전체 카테고리 + 사용자의 기존 선택 로드
  2. 매핑해서 setData() 한 번에 세팅
  3. 저장 시 getValue()로 선택된 코드 배열 획득 → 서버 전송

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

  1. Va.Component 상속 — PureField 계열이 아님. focus(), getValue() API가 다른 필드와 약간 다름.
  2. getValue()는 배열 — 단일 값이 아님. 서버 전송 시 배열 처리 필요.
  3. setValue()도 배열 전달 — 단일 값도 자동으로 배열로 감싸지만, 처음부터 배열로 넘기는 게 명확.
  4. change 인자는 변경된 항목의 key — 전체 선택 배열이 아니라. 전체 상태는 getValue() 재호출.
  5. removeData / modifyData 없음 — 전체 교체는 setData().
  6. addData는 새 항목을 기본 체크된 상태로 추가 — 코드가 checked: true로 고정 (va_component.js:10927). 미체크로 추가하려면 데이터에서 조작 후 setData() 재호출.
  7. insertData(item, index)의 위치 로직 미묘 — 코드가 append 후 insertBefore를 함께 호출해 실제 동작 확인 권장.
  8. 데이터 필드명 name 조심 — HTML name 속성으로 자동 세팅되므로 사용자 이름 같은 실데이터를 이 필드명으로 두지 말 것.
  9. setData()는 자식 전체 제거 후 재렌더 — 기존 선택 상태 사라짐. 유지가 필요하면 getValue()로 백업 후 setData() → setValue() 재세팅.
  10. direction CSS 클래스로 반영 — 실제 flex 방향은 CSS(va.css 계열)에서 정의.
  11. 자식 checkbox의 valueType 지정 안 됨 — 그룹에서 관리하는 값은 항상 key 배열. 개별 체크박스의 valueType 옵션이 무시됨.
  12. 키보드 조작 — 각 체크박스는 스페이스로 토글 가능 (Checkbox의 표준 동작).

13. checkboxGroup vs checkboxGroupField vs combobox multi

상황추천

폼 안, 라벨·검증 필요 checkboxGroupField
폼 아닌 인라인, 간단 선택 checkboxGroup
옵션 5개 이하 checkboxGroup
옵션 20개 이상 combobox + multiSelect: true (드롭다운)
선택된 항목을 칩으로 표시 Va.Tag
한 화면에 세로로 나열 (설정 화면 등) checkboxGroup + direction: 'vertical'



'컴포넌트 > 필드 컴포넌트' 카테고리의 다른 글

Radio (라디오 버튼)  (0) 2026.09.12
CheckboxGroupField (체크박스그룹필드)  (0) 2026.09.12
CheckboxField (체크박스필드)  (0) 2026.09.12
Checkbox (체크박스)  (0) 2026.09.12
TimeField (시각필드)  (0) 2026.09.12