컴포넌트/필드 컴포넌트

MonthField (년월필드)

VanillaFront 2026. 9. 12. 19:00

Va.MonthField — 라벨 + 년-월 선택 필드

Va.MonthPicker가 순수 년-월 입력이라면, Va.MonthField는 그 위에 라벨·필수 표시·검증 메시지를 얹은 완성 폼 필드입니다. Field 계열 아키텍처 그대로, 내부에 Va.MonthPicker를 소유하는 Composition 구조. DateField·YearField와 같은 형제로, 월간 리포트·월별 필터 폼에 정확히 맞습니다.

  • 클래스: Va.MonthField  va_component.js:8743
  • short name: monthField
  • 상속: Va.Field (다른 Field 형제들과 같음)
  • 내부 컴포넌트: Va.MonthPicker 인스턴스 (fieldComponent)
  • isContainer: true
  • 베이스 CSS: va-field (role="date-field" 자동 부여)


1. 기본 사용

{
    tagName: 'monthField',
    label: '대상 월',
    value: '202412',              // YYYYMM 6자리
    required: true,
    onSelect: 'onMonthChange'
}

라벨 + 검증 + 12개월 격자 팝업이 한 번에 세팅. 저장 값은 6자리 문자열.


2. Field 계열에서의 위치

Va.Field
   ├─ Va.InputField         ← Va.Input
   ├─ Va.SearchField        ← Va.Search
   ├─ Va.NumberField        ← Va.Number
   ├─ Va.ComboboxField      ← Va.Combobox
   ├─ Va.YearField          ← Va.YearPicker        (년만)
   ├─ Va.MonthField         ← Va.MonthPicker       (년-월)         ← 이 문서
   ├─ Va.DateField          ← Va.DatePicker        (년-월-일)
   ├─ Va.DateTimeField      ← Va.DateTimePicker    (년-월-일 + 시분초)
   └─ ...

MonthField의 정체: Field 베이스 + 내부에 Va.MonthPicker 인스턴스.

⚠️ 다른 Field 형제와 함께 "Picker"가 이름에서 생략되는 그룹. 등록명은 monthField.


3. Va.MonthPicker / 다른 Date 계열 Field와의 차이

항목Va.MonthPickerVa.MonthFieldVa.YearFieldVa.DateField

라벨
검증 메시지
info 툴팁
입력 대상 년-월 년-월 년만 년-월-일
저장 값 길이 6자리 6자리 4자리 8자리
팝업 UI 12개월 격자 12개월 격자 (내부 위임) 10년 격자 일 단위 캘린더
role="date-field" 자동
setValue() / getValue() 오버라이드 원본 부모(Field) 상속 없음 (단순 통과) 있음 (포맷 변환)

한 줄 요약: "폼 안 라벨 붙은 년-월 필드 — 월간 리포트에 최적."


4. 주요 속성

날짜 포맷

속성기본값설명

dateFormat 'ym' 화면 순서 — ym / my
dateSeperator '-' 화면 구분자
valueDateFormat 'ym' 저장 값 순서
valueDateSeperator '' 저장 값 구분자
masking 자동 (____-__ 또는 __-____) dateFormat에 따라 자동

팝업

속성기본값설명

popWidth 240 팝업 폭
expanded false 초기 상태
min / max properties에 있으나 MonthPicker에서 강제 로직 없음

라벨 (Field 상속)

속성설명

label 라벨 텍스트 또는 객체
labelPosition top / bottom / left / right
labelWidth 라벨 폭
noLabel 라벨 숨김
infoButton info 아이콘
required 필수 표시

필드 관련 (MonthPicker로 위임)

속성설명

value 년-월 값 (YYYYMM 문자열)
placeholder 플레이스홀더
readonly / disabled 상태
size / appearance / shape 시각 스타일
textAlign 정렬
stopPropagation 이벤트 버블링

검증

속성설명

validation {state, size, message}
validationState success / warning / error
validationMessage 메시지

세부 커스터마이즈 (monthPicker 옵션 키)

{
    tagName: 'monthField',
    label: '대상 월',
    monthPicker: {                // ← 내부 MonthPicker에 전달
        popWidth: 320
    }
}

MonthField는 옵션 키가 정확히 monthPicker — YearField(잘못 남은 monthPicker)와 달리 이건 의도된 매핑입니다.

각 Field 계열 옵션 키:

  • InputField → input
  • ComboboxField → combobox
  • DateField / DateTimeField → datePicker
  • YearField → monthPicker (잔재)
  • MonthField → monthPicker (정상)

5. 이벤트

MonthPicker의 이벤트를 재발화:

이벤트시그니처발생 시점

select (component, element, value, evt) 팝업에서 월 클릭 시. value는 선택된 값
beforePop / afterPop / hidePop 팝업 표시/숨김  
expand / collapse 팝업 확장/축소  
focus / blur 표준  
change / keydown Field 표준  

주목: select 콜백 시그니처에 value 인자가 전달됩니다. DateField는 인자가 짧아 component.getValue()로 조회해야 했지만, MonthField는 직접 받을 수 있어요.


6. 메서드

값 관리 (Field 상속 그대로)

메서드설명

getValue() 내부 MonthPicker의 getValue() 위임 (valueDateFormat 규약)
setValue(value) Field 상속 — 포맷 변환은 내부 MonthPicker에 위임

주목: MonthField는 setValue() / getValue()를 오버라이드하지 않습니다. DateField·DateTimeField는 자체 재구현했지만, MonthField는 Field 베이스의 것을 그대로 사용 — 값 처리는 전적으로 내부 MonthPicker에 위임됩니다.

상태 (Field 상속)

메서드설명

setDisabled(bool) / getDisabled() 비활성화
setReadOnly(bool) / setReadonly(bool) 읽기 전용
setLabel(label) 라벨 변경
setPlaceholder(text) 플레이스홀더
setSize(size) 크기

검증

메서드설명

setValidation(state, message) 검증 표시 + aria
clearValidation() 검증 해제

포커스

메서드설명

focus() / blur() 내부 MonthPicker의 fieldElement에 위임

주의: showMonthPickerPop, hideMonthPickerPop, setRawValue, getRawValue 같은 MonthPicker 세부 메서드는 위임 없음. 필요하면 component.fieldComponent.xxx()로 직접.


7. 내부 구조

<div elname="element" class="va-field [vertical|horizontal]"
     role="date-field" 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-monthpicker">     ← 내부 Va.MonthPicker
        <div class="field-wrapper">
          <input type="text" placeholder="____-__">
          <div class="focus-line"></div>
          <div class="calendar-icon-wrapper">
            <span class="icon menu ico_calender_ltr">📅</span>
          </div>
        </div>
        <!-- 팝업은 hiddenArea로 이동 -->
      </div>
    </div>
  </div>
  <div elname="validationDiv" style="display:none">
    <div class="va-validation">...</div>
  </div>
</div>

8. 마스킹 이중 설정

DateField와 마찬가지로 생성자에서 마스킹을 두 번 설정합니다:

  1. option.masking = '____-__'로 초기값 세팅 (va_component.js:8754)
  2. optionField.masking에 넣어 MonthPicker 생성자로 전달
  3. MonthPicker 생성 후 this.fieldComponent.setMasking(this.masking) 재호출 (va_component.js:8813)

의도는 dateFormat이 바뀌어도 정확한 마스킹 패턴이 반영되도록 하기 위함.


9. 언제 쓰나

MonthField가 맞을 때

  • 폼 안 월별 리포트 필터 — 대상 월 선택
  • 월별 예산·매출 등록
  • 월간 근태·급여 대상 월
  • 분기 통계 (월 선택으로 분기 유추)
  • 라벨·필수·검증이 필요한 폼 필드

다른 걸 쓸 때

  • 라벨 없이 인라인 → Va.MonthPicker
  • 년도만 필요 → Va.YearField
  • 년-월-일 필요 → Va.DateField
  • 시간까지 → Va.DateTimeField
  • 년-월을 두 개 콤보로 → Va.ComboboxField 두 개 조합
  • 최근 몇 개월 목록만 → Va.ComboboxField (동적 데이터)

10. 흔한 조합 예시

// 표준
{
    tagName: 'monthField',
    label: '대상 월',
    value: '202412',
    required: true
}

// 미국식 표시
{
    tagName: 'monthField',
    label: 'Month',
    dateFormat: 'my',
    dateSeperator: '/',
    valueDateFormat: 'ym',
    value: '202412'          // 화면: 12/2024, 저장: 202412
}

// 서버가 하이픈 포함 원할 때
{
    tagName: 'monthField',
    label: '결산 월',
    valueDateSeperator: '-',
    value: '2024-12'
}

// 좌측 라벨
{
    tagName: 'monthField',
    label: '기준 월',
    labelPosition: 'left',
    labelWidth: 100,
    value: '202412'
}

// 오늘 년-월로 초기화
mounted() {
    const now = new Date();
    const ym = now.getFullYear() +
               String(now.getMonth() + 1).padStart(2, '0');
    this.getRef('month').setValue(ym);
}

// info 툴팁
{
    tagName: 'monthField',
    label: '급여 지급 월',
    infoButton: {
        tooltip: '급여가 지급되는 월을 선택하세요'
    }
}

// 검증
{
    tagName: 'monthField',
    label: '대상 월',
    ref: 'month',
    required: true,
    onSelect: 'onMonthPicked'
}

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

  1. 컴포넌트명  monthField (not monthPickerField).
  2. value는 6자리 문자열  '202412' 형태. Date 객체 안 됨.
  3. setValue() / getValue()가 오버라이드되어 있지 않음 — 값 처리는 내부 MonthPicker에 위임. 포맷 변환도 MonthPicker의 것 그대로.
  4. dateFormat / valueDateFormat 혼동 주의 — 화면 vs 저장.
  5. 마스킹 자동 — dateFormat에 따라 자동 설정. 사용자 지정 시 덮어씀.
  6. 필드에 잘못된 값 타이핑 가능 — 마스킹은 자릿수만. 9999-99 같은 값 들어감. 별도 검증 필요.
  7. 옵션 키 monthPicker — 정확히 이 키. YearField와 동일하지만 YearField는 잔재라 반영 안 됨. MonthField는 정상 반영.
  8. popWidth 기본 240 — DatePicker(260)보다 작음. 12개월 격자엔 충분.
  9. min/max 실질 강제 없음 — MonthPicker 자체가 범위 필터 없음.
  10. 팝업 상태머신 참여 — 다른 팝업과 자동 상호 배타.
  11. role="date-field" 자동 — Month이지만 role은 date-field. ARIA 힌트.
  12. 일부 메서드 위임 누락  showPop/hidePop/setRawValue/getRawValue. fieldComponent로 직접.
  13. timezone은 KST 기준 — 내부 MonthPicker가 한국 시간대 계산. UTC 정확도 중요하면 확인.

12. 실전 예 — 월별 매출 리포트 (Field 버전)

MonthPicker 편의 예제를 Field로 감싼 버전:

class MonthlySalesReport extends Va.View {
    mounted() {
        // 지난 달로 초기화
        const now = new Date();
        now.setMonth(now.getMonth() - 1);
        const lastMonth = now.getFullYear() +
                          String(now.getMonth() + 1).padStart(2, '0');
        this.getRef('month').setValue(lastMonth);
        this.loadReport(lastMonth);
    }

    onMonthSelect(field, el, value, evt) {
        this.loadReport(value);
    }

    loadReport(yyyymm) {
        if (!yyyymm || yyyymm.length !== 6) {
            this.getRef('month').setValidation('error', '월을 선택하세요');
            return;
        }
        this.getRef('month').clearValidation();

        SalesService.getMonthly(this, { yyyymm }, (view, ok, res) => {
            if (ok) view.getRef('grid').setData(res.data.list);
        });
    }

    config() {
        return {
            tagName: 'page',
            tags: [{
                tagName: 'panel',
                tags: [
                    { tagName: 'h2', innerHTML: '월별 매출 리포트' },
                    {
                        tagName: 'div',
                        layout: 'ds-flex fd-row ai-end gap-s',
                        tags: [
                            {
                                tagName: 'monthField',
                                ref: 'month',
                                label: '대상 월',
                                required: true,
                                onSelect: 'onMonthSelect',
                                style: { width: '180px' }
                            }
                        ]
                    },
                    {
                        tagName: 'grid',
                        ref: 'grid',
                        columns: [
                            { key: 'day',     title: '일',   width: 60 },
                            { key: 'revenue', title: '매출', fillRatio: 1 },
                            { key: 'orders',  title: '건수', width: 100 }
                        ]
                    }
                ]
            }]
        };
    }
}

MonthPicker 단독 사용과 비교하면 라벨 + 필수 표시 + 검증 메시지가 자동 세팅되어 폼 UX가 자연스럽습니다.


13. monthField vs 다른 Field 선택 기준

상황추천

월별 매출·통계 리포트 필터 monthField
급여 지급 월, 결산 월 monthField
정확한 날짜(일)까지 필요 Va.DateField
년도만 (연간 리포트) Va.YearField
시간까지 필요 Va.DateTimeField
시작-종료 월 범위 두 MonthField 조합
년/월을 별개 UI로 (드롭다운 두 개) Va.ComboboxField × 2
최근 12개월 목록만 선택 Va.ComboboxField (동적 데이터)