컴포넌트/필드 컴포넌트

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