Form
Form은 서로 관련된 필드를 수집하고 검증한 뒤 제출하는 컴포넌트입니다. 신청, 등록, 설정, 레코드 편집, 워크플로 단계에 사용할 수 있습니다. Form은 섹션, 레이아웃, 검증 상태와 제출 범위를 하나의 계약으로 관리합니다.
1. Form 기능과 구성 항목
Form 구성은 네 가지 수준으로 나뉩니다.
- Form은 레이아웃, 모드, 데이터 로드, 제출, 초안과 공개 상태를 관리합니다.
- Form Section은 업무 주제별로 필드를 구성하며 반복 컬렉션으로 설정할 수도 있습니다.
- Field는 레이블, Field Key, 초기값, 행 점유 방식, 조건과 검증 규칙을 정의합니다.
- Button Set / Interaction은 Reset, Validate, Submit과 컴포넌트 함수를 조합합니다.
1.1 속성과 기능 개요
| 구성 영역 | 주요 속성 또는 기능 | 용도 |
|---|---|---|
| 구조 | ID / Name, Form Sections, Fields, Button Set | Form 경계, 업무 그룹과 제출 범위를 정의 |
| 레이아웃 | Controls Per Row, Form column split, Layout, Label Alignment, Full row | 필드 수, 레이블 폭, 배치와 전체 행 필드를 조정 |
| 모드 | Create, Edit, View, Warn about unsaved changes | 생성, 편집, 읽기 전용과 저장되지 않은 변경 경고를 관리 |
| 데이터 어댑터 | Load / Create / Update URL, Response Data Path, Record ID, Revision | 레코드를 로드하고 낙관적 잠금 API에 연결 |
| 제출 | Full values, Changed values only, Custom URL | 전체 값 또는 변경된 값만 제출 |
| 검증 | Required, Length, Pattern, Number, Custom Validator, Remote validation | 로컬, 원격과 서버 필드 오류를 표시 |
| 조건 | Visible / Disabled / Required When, Dependencies, Clear When Hidden | 다른 필드, Page Context 또는 현재 모드에 반응 |
| 반복 그룹 | Collection Key, Minimum / Maximum Items, Add / Delete | 연락처나 상세 행 같은 객체 배열을 편집 |
| 초안 | Browser / Remote storage, Draft Key, Autosave Delay, revision | 완료되지 않은 입력을 저장, 복원 또는 폐기 |
| 작업과 상태 | reset, validate, submit, saveDraft, restoreDraft, discardDraft, forms.* | 작업을 구성하고 valid, dirty, submitting 상태를 조회 |
| 필드 생성 | Business Object, JSON Schema, OpenAPI | 기존 모델에서 편집 가능한 필드 구조를 생성 |
1.2 구조와 제출 범위
Form은 상태와 제출 범위의 경계입니다. 한 페이지에 여러 Form이 있어도 각 Form은 자신의 Sections, Fields, Button Set만 관리합니다.
- Form Section은 업무 그룹을 표현하며 단순한 시각적 여백이 아닙니다.
- Field Key는 Form 상태와 제출 JSON의 안정적인 이름이며 백엔드 DTO와 일치해야 합니다.
- Button Set은 작업을 배치하고, 실제 Reset, Validate, Submit 동작은 Interaction에서 지정합니다.
- Submit Form은 대상 Form에 등록된 필드만 수집하며 다른 Form, Page Context, Tree Current Record를 자동으로 포함하지 않습니다.
검색 Form과 편집 Form을 한 페이지에 배치한다면 서로 다른 ID를 지정하고 각 작업이 올바른 Form을 명시적으로 가리키게 하십시오.
1.3 레이아웃과 반응형 동작
Controls Per Row는 행당 최대 필드 수와 각 필드의 그리드 폭을 결정합니다. Form column split은 이 영역을 Label과 Content로 나누며, 행당 두 필드일 때 합계는 12, 한 필드일 때는 24입니다.
Layout은 Horizontal, Vertical, Inline을 지원합니다. Label Alignment는 Horizontal의 레이블 텍스트에만 적용됩니다. Full row / Start on new row는 긴 필드가 전체 행을 차지하면서 일반 필드의 첫 레이블과 정렬되게 합니다. 좁은 화면에서는 읽기 순서대로 쌓이므로 모바일 전용 Form이 필요하지 않습니다.
1.4 모드, 데이터 로드와 제출
| 모드 | 동작 | 일반적인 엔드포인트 |
|---|---|---|
| Create | 초기값으로 새 레코드를 생성 | Create URL, 일반적으로 POST |
| Edit | 레코드를 로드한 뒤 변경 사항을 제출 | Load URL + Update URL, 일반적으로 PUT / PATCH |
| View | 같은 레이블/값 구조를 읽기 전용으로 표시 | Load URL, 편집 작업 없음 |
Data adapter는 Response Data Path에서 레코드를 찾고 Record ID Field, Revision Field로 식별자와 낙관적 잠금을 유지합니다. 로드된 값은 Reset과 Changed values only의 기준선이 됩니다. 단순 제출에는 Custom URL을 사용하고, 로드, 편집, 충돌 감지, 초안 복원이 필요하면 전체 Data adapter를 구성합니다.
1.5 검증, 필드 오류와 조건
Required, Length, Pattern, Number, Custom Validator는 즉시 로컬 검증을 제공합니다. Remote validation은 이메일, 사용자 이름, 업무 코드 등을 백엔드에서 확인하며 트리거와 Debounce를 설정할 수 있습니다. 제출 시 백엔드가 fieldErrors를 반환하면 Form은 Field Key를 기준으로 해당 필드에 메시지를 표시합니다.
Visible When, Disabled When, Required When은 state.*, context.*, record.*, form.*을 읽습니다. Dependencies는 다시 계산할 Field Key를 선언하고 Clear When Hidden은 숨겨진 이전 값을 제거합니다. 클라이언트 검증이나 필드 숨김은 서버 검증과 권한을 대신하지 않습니다.
1.6 반복 그룹과 초안
반복 Form Section에서는 내부 Fields가 한 행의 템플릿이 됩니다. Collection Key는 제출 JSON의 객체 배열이며 Minimum / Maximum Items가 행 수를 제한하고 Runtime이 Add / Delete를 제공합니다. 오류 경로에는 배열 인덱스가 유지되어 문제가 있는 행을 찾을 수 있습니다.
초안은 저장된 업무 레코드가 아니라 아직 제출하지 않은 Form 상태입니다. Browser storage는 한 기기의 단기 입력에 적합하고, Remote service는 Load / Save URL, Draft Key, revision을 사용해 여러 기기나 중요한 입력을 지원합니다. revision 충돌은 복원 또는 다시 로드를 안내해야 하며 조용히 덮어쓰면 안 됩니다.
1.7 작업과 공개 상태
| 작업 | 동작 |
|---|---|
reset | 로드된 기준선 또는 Create 초기값으로 복원하고 오류를 제거 |
validate | 현재 Form을 검증하고 실패하면 후속 작업을 중단 |
submit | 검증, payload 생성, 요청 전송과 필드 오류 처리를 수행 |
saveDraft / restoreDraft / discardDraft | 초안을 저장, 복원 또는 폐기 |
표현식은 forms.<formId>.valid, dirty, submitting, submitError, lastSubmit, mode를 읽을 수 있습니다. 이 상태는 읽기 전용입니다. Step에서는 Submit Form이 성공한 뒤에만 nextStep을 실행하도록 작업 체인을 구성할 수 있습니다.
1.8 필드 생성과 백엔드 협력
Generate fields는 Business Object, JSON Schema, OpenAPI Schema에서 Sections와 Fields를 생성합니다. 결과는 일반 페이지 메타데이터이므로 레이블, 민감한 필드, 선택지, 권한, 레이아웃과 API를 계속 수정하고 검토할 수 있습니다.
데이터 로드, 원격 검증, 초안과 제출 요청에는 X-Spark-Page-Environment, X-Spark-Page-Render-Mode가 자동으로 포함됩니다. 백엔드는 DESIGN_PREVIEW에서 안정적인 테스트 데이터를, RUNTIME에서 실제 Use Case를 실행할 수 있지만 인증, 테넌트 격리와 권한은 별도로 적용해야 합니다.
1.9 구성 선택 가이드
| 목표 | 권장 시작 설정 | 참고 절 |
|---|---|---|
| 기본 생성 Form | Create + Sections + 로컬 검증 + Custom URL | 2~8 |
| 기존 레코드 편집 | Edit + Load / Update URL + Record ID / Revision | 9, 10, 14 |
| 읽기 전용 상세 | View + Load URL | 10 |
| 동적 필드 | Conditions + Dependencies | 11, 12 |
| 연락처 또는 상세 행 | Repeatable Group | 13 |
| 장시간 입력 | Draft + 저장되지 않은 변경 경고 | 15 |
| 모델에서 생성 | Generate fields | 16 |
1.10 Form에서 사용할 수 있는 필드
먼저 데이터 형태에 맞는 필드를 선택한 다음 레이아웃, 검증 및 Interaction을 구성합니다. 현재 필드 팔레트에는 아래 22개 컴포넌트가 표시됩니다. 이전 Select, MultiSelect 및 구 MultiRowInput은 기존 페이지 호환을 위해 숨겨져 있으며 새 페이지의 추가 항목이 아닙니다.
| 분류 | 필드 컴포넌트 | 적합한 데이터 |
|---|---|---|
| 기본 입력 | Input, Address, Text Area | 한 줄 텍스트, 주소 및 긴 텍스트 |
| 선택 및 사용자 | Select, Radio Button, Checkbox, Switch, Cascade Select, Tree Select, Transfer, User Select, Department Select | enum, 계층, 집합, 사용자 ID 및 부서 ID |
| 날짜 및 숫자 | Date Picker, Time Picker, Calendar, Rate, Slider | 날짜, 시간, 평점, 숫자 및 범위 |
| 편집기 | Rich Text, Code Editor, JSON Editor | 서식 있는 본문, 스크립트 및 JSON |
| 파일 및 구조화 데이터 | Upload, Multi-Row Input | 파일 메타데이터 및 객체 배열 |
각 필드 문서는 사용 시점, 주요 속성, 제출 값 형태, 조건 및 Interaction을 설명합니다. 외형만 보지 말고 백엔드 데이터 계약을 기준으로 선택하세요.
2. 예제: 직원 온보딩 요청
Spark Sample의 Form 페이지는 두 개의 섹션, 2열 배치, 전체 행 사유 필드와 Reset / Validate / Submit 작업을 보여 줍니다.
Screen
└── Form: Employee Onboarding Form
├── Employee details
│ ├── Full name / Work email / Department
│ └── Employment type / Start date
├── Equipment and access
│ ├── Laptop budget / Administrator access
│ └── Request justification (전체 행)
└── Reset / Validate / Submit request
3. Form과 섹션 추가
- Screen, Panel, Grid Column, Tab, Step 또는 Content에 Form을 추가합니다.
- Form을 선택하고 Form Sections에 하나 이상의 섹션을 추가합니다.
- 각 섹션의 Fields에 Field, Select, RadioBox, DatePicker, Switch, TextArea 등을 추가합니다.
- Form의 Button Set에 작업 버튼을 추가합니다.
- Form과 각 필드에 안정적인 ID / Name을 지정하고 저장한 뒤 디자인 화면과 Runtime을 모두 확인합니다.
섹션은 기본 정보, 접근 권한, 첨부 파일, 확인처럼 업무 의미에 따라 나눕니다. 여백만 만들기 위한 빈 섹션은 사용하지 마십시오.
4. 레이아웃
Controls Per Row는 한 행에 배치할 일반 필드의 최대 개수입니다. PC 업무 Form은 2, 긴 내용이나 좁은 영역은 1, 짧은 검색 조건은 3 또는 4가 적합합니다. 좁은 화면에서는 읽기 순서대로 한 열에 쌓입니다.
Form 내부는 24열 그리드를 사용하지만 분할은 각 필드 영역 안에서 계산합니다. 한 행에 두 필드를 배치하면 각 필드가 12열을 받습니다.
Label 4 + Content 8 = 12
한 행에 한 필드라면 6 + 18처럼 합계 24를 사용합니다. Form column split 눈금을 드래그하면 두 값이 함께 변경됩니다.
TextArea 등에 Start on new row / Full row를 켜면 레이블은 현재 Form 비율을 유지하면서 위 행의 첫 레이블과 정렬되고, 콘텐츠만 나머지 열을 가로지릅니다.
| Layout | 사용 목적 |
|---|---|
| Horizontal | 레이블과 입력을 같은 행에 배치하는 일반 업무 Form |
| Vertical | 좁은 영역이나 긴 레이블에서 레이블을 입력 위에 표시 |
| Inline | 짧은 검색/필터 바에서 필드와 버튼을 한 줄로 배치 |
5. 예제 필드
| 필드 | 컴포넌트 | 주요 설정 |
|---|---|---|
| Full name | Field | Required, Length 2–60 |
| Work email | Field | Required, 이메일 Pattern |
| Department | Select | 고정 옵션 4개 |
| Employment type | RadioBox | 옵션 3개 |
| Start date | DatePicker | YYYY-MM-DD |
| Laptop budget | Number Field | 500–5000, 접미사 USD |
| Administrator access | Switch | Default Checked 끔 |
| Request justification | TextArea | 전체 행, 높이 4–8, Length 20–500 |
Name / Field Key는 백엔드로 보내는 JSON 속성명이 됩니다. 같은 Form의 편집 가능한 필드는 서로 다른 키를 사용해야 합니다.
6. 검증
Required는 빈 값, Length는 문자열 길이, Pattern은 이메일 같은 형식, Number는 숫자 범위, Custom Validator는 업무 규칙에 사용합니다. 실패하면 Spark가 해당 필드 근처에 오류를 표시하고 제출을 중단합니다.
브라우저 검증은 즉각적인 피드백을 위한 것입니다. 요청은 화면을 우회할 수 있으므로 백엔드에도 같은 검증을 유지해야 합니다.
7. Reset, Validate, Submit
Reset 버튼의 onClick에 Call Component Function을 추가합니다.
Component: employee_onboarding_form
Function: reset
Reset은 초기값을 복원하고 검증 메시지를 지웁니다. Validate에는 Validate Form을 추가하고 같은 Form을 선택합니다.
Submit 설정:
Form: employee_onboarding_form
Submission Mode: Custom URL
URL: /spark/api/sample/form/requests
Method: POST
Spark는 선택한 Form을 검증하고 그 Form에 등록된 필드만 JSON으로 전송합니다. 다른 Form, Page Context, Tree Current Record는 payload에 섞이지 않습니다.
8. Java 백엔드와 페이지 컨텍스트
@PostMapping
public ApiResult<FormRequestReceiptDTO> submit(
@RequestBody FormRequestSubmission request,
@RequestHeader(value = SparkPageRequestHeaders.ENVIRONMENT,
required = false) String environment,
@RequestHeader(value = SparkPageRequestHeaders.RENDER_MODE,
required = false) String renderMode) {
SparkPageRequestContext context =
SparkPageRequestHeaders.resolve(environment, renderMode);
return SparkApiResultHelper.success(
Locale.KOREAN,
requestService.submit(request, context),
"SPARK-SAMPLE-FORM-0001");
}
DESIGN_PREVIEW에서는 저장하지 않는 안정적인 미리보기 영수증을 반환하고, RUNTIME에서는 실제 UseCase를 실행할 수 있습니다. Spark가 X-Spark-Page-Environment와 X-Spark-Page-Render-Mode를 자동으로 추가하므로 각 Interaction에 반복 입력하지 마십시오. 자세한 내용은 페이지 요청 컨텍스트를 참고하십시오.
9. 고급 예제: 직원 프로필 편집
두 번째 예제는 레코드 로드, 이메일 원격 검증, 조건부 관리자 권한 사유, 긴급 연락처 추가/삭제, 초안 자동 저장, 변경 필드만 제출하는 전체 편집 흐름을 보여 줍니다.
재현 가능한 페이지는 form-capabilities-page.json, 백엔드는 FormCapabilityController와 FormCapabilitySampleService에 있습니다.
10. 모드와 공개 상태
Form capabilities에서 Create / Edit / View를 선택합니다. Edit는 Load URL에서 읽고 Update URL로 저장하며, View는 같은 레이아웃을 읽기 전용으로 표시합니다. 미저장 변경 경고도 활성화할 수 있습니다.
forms.employee_profile_form.valid
forms.employee_profile_form.dirty
forms.employee_profile_form.submitting
forms.employee_profile_form.submitError
forms.employee_profile_form.lastSubmit
forms.employee_profile_form.mode
Form 내부에서는 form.dirty, form.submitting을 사용할 수 있습니다. 이 상태는 읽기 전용입니다.
11. 조건부 필드
Visible When: state.adminAccess === true
Required When: state.adminAccess === true
Dependencies: adminAccess
Clear When Hidden: on
Visible / Disabled / Required는 state.*, context.*, record.*, form.* 불리언 표현식을 사용합니다. Dependencies에는 안정적인 Field Key를 쉼표로 구분해 입력합니다. Clear When Hidden은 숨겨진 오래된 값을 제출하지 않도록 제거합니다.
12. 원격 검증과 서버 필드 오류
Work email의 Validators에 Remote validation을 추가합니다.
Validation URL: /spark/api/sample/form/validate-email
Method: POST
Debounce: 400
Valid Response Path: data.valid
Message Response Path: data.message
Trigger: blur
새 입력은 이전 요청을 취소하고 오래된 응답은 무시합니다. 저장 시 업무 검증은 Field Key별 오류를 반환합니다.
{
"success": false,
"fieldErrors": {
"workEmail": ["이미 사용 중인 이메일입니다."],
"adminAccessReason": ["관리자 권한이 필요한 이유를 입력하십시오."]
}
}
Java에서는 SparkFieldValidationException과 Lattice Message를 사용해 Web 경계에서 언어를 적용합니다.
13. 반복 그룹
Form Section에서 Repeatable Group을 켭니다.
Collection Key: emergencyContacts
Minimum Items: 1
Maximum Items: 3
Add Button Text: Add contact
Section의 필드가 행 템플릿이 되고 Runtime이 Add/Delete와 배열 검증 경로를 관리합니다. View 모드에서는 편집 작업이 표시되지 않습니다.
14. 데이터 어댑터와 변경 집합
Load URL: /spark/api/sample/form/records/employee-1001
Create URL: /spark/api/sample/form/records
Update URL: /spark/api/sample/form/records/[[state.id]]
Response Data Path: data
Submission Payload: Changed values only
Record ID Field: id
Revision Field: revision
Edit는 로드 후 기준값을 만들고 recordId, revision, add/replace/remove 형식의 changes를 보냅니다. Create는 항상 전체 값을 보냅니다. 오래된 revision은 HTTP 409로 거부해야 합니다.
15. 초안 자동 저장
개인 임시 입력은 Browser storage, 여러 기기에서 이어야 하는 중요한 흐름은 Remote service를 사용합니다. Draft Key, Autosave Delay, Load URL, Save URL을 설정합니다. saveDraft, restoreDraft, discardDraft를 버튼에서 호출할 수 있습니다. 원격 초안은 저장 후 새 revision을 반환해야 합니다.
16. 모델 또는 Schema에서 필드 생성
Form capabilities → Generate fields에서 Business Object, JSON Schema 또는 OpenAPI를 선택하고 Append/Replace를 실행합니다. 객체 배열은 Repeatable Group이 됩니다. 결과는 일반 편집 가능한 페이지 메타데이터이며 Runtime은 백엔드가 반환한 임의 컴포넌트 JSON이나 스크립트를 실행하지 않습니다.
생성 후 레이블, 민감 필드, 옵션, 권한, URL과 서버 검증을 점검하십시오.
17. 문제 해결
- 레이블이 정렬되지 않음: 한 행에 두 필드라면
4 + 8처럼 합계 12를 사용합니다. - 조건부 필드가 갱신되지 않음: Dependencies에 제어 필드의 Field Key를 입력하고 표시 레이블은 사용하지 마십시오.
- 서버 오류가 상단에만 표시됨: 루트
fieldErrors의 키를 정확한 Field Key로 반환합니다. - 초안 충돌이 반복됨: 저장 응답의 새 revision을 다음 저장 요청에 포함합니다.
- 디자인 미리보기에서 실제 레코드가 생성됨:
DESIGN_PREVIEW에서는 미리보기 결과나 샌드박스를 사용합니다.