화면 개발 및 거래 업무 사용법 (syn.$w)
개요
syn.$w(별칭: $webform)는 syn.js에서 가장 큰 하위 모듈로, 화면 부트스트랩(페이지 로드/포커스 관리), 로컬/세션 스토리지, 동적 스크립트/스타일 로딩, IntersectionObserver 기반 지연 로딩, 그리고 HandStack 백엔드와 통신하는 거래(transaction) 엔진까지 화면 개발에 필요한 핵심 기능을 담당합니다.
로드 방법
syn.js가 로드되면 전역에 syn.$w(별칭: $webform)로 즉시 사용할 수 있습니다. 화면(HTML) 진입 시 syn.loader.js가 syn.$w.contentLoaded()를 자동으로 1회 호출하여 페이지 부트스트랩을 수행합니다.
빠른 시작
// 세션 스토리지에 값 저장/조회
syn.$w.setStorage('lastVisited', new Date());
var lastVisited = syn.$w.getStorage('lastVisited');
// 거래 요청/응답 매핑 설정(예: GD01)이 있는 화면에서 거래 실행
syn.$w.transactionAction('GD01');
주요 시나리오
페이지 부트스트랩(contentLoaded)
contentLoaded()는 document의 DOMContentLoaded 시점(또는 설정 파일 로드 완료 시점)에 자동으로 호출되어 다음을 처리합니다.
<form>제출(submit) 이벤트 가로채기 및hook.beforeSubmit연동- SSO 사용자 정보(
syn.$w.User)를hook.getSSOInfo()또는 기본값으로 초기화하고deepFreeze처리 - 미디어 쿼리 구간(
xs~xxl) 변경 시hook.pageMatch()호출 - 화면 내 컨트롤의 탭 순서(tabOrderControls) 계산
- 완료 후 현재 페이지 모듈의
hook.pageLoad()실행
페이지 진입 시 이미 자동 실행되므로, 직접 호출할 필요는 거의 없습니다. 현재 상태는 syn.$w.pageScript, syn.$w.isPageLoad 속성으로 확인할 수 있습니다.
console.log(syn.$w.pageScript); // 예: '$webforms'
페이지 준비 완료 대기
컨트롤의 데이터 소스 로딩 등 화면 초기화가 모두 끝난 뒤(= hook.pageLoad() 실행 시점, syn.$w.isPageLoad === true) 실행할 코드는 다음 API로 대기할 수 있습니다. 내부적으로 syn.$w.addReadyCount() / removeReadyCount() 로 집계되는 준비 카운터가 0이 되는 시점에 일괄 실행됩니다.
syn.$w.readyAsync()→Promise<void>— 페이지 준비 완료를 Promise로 대기. 이미 준비되었으면 즉시 resolve.syn.$w.ready(callback)— 콜백 전달 시 준비 완료 시(또는 즉시) 실행하고syn.$w반환. 콜백 미전달 시readyAsync()반환.syn.$w.withReadyCount(promise | function)→Promise— 전달한 비동기 작업이 끝날 때까지 페이지 준비 완료(pageLoad)를 지연시킵니다. 컨트롤이 비동기 리소스를 로드하는 동안 화면 코드가 빈 상 태로 실행되는 것을 방지합니다.
await syn.$w.readyAsync();
// 이 시점에는 모든 컨트롤의 데이터 소스가 채워져 있음
syn.$w.ready(function () {
syn.$l.get('txtName').focus();
});
// 컨트롤 개발자: 비동기 초기화를 페이지 준비 카운터에 연동
syn.$w.withReadyCount(async function () {
await syn.$w.loadScriptAsync('/lib/thirdparty/lib.min.js', 'thirdpartyLib');
});
로컬/세션 스토리지 TTL 관리
setStorage(prop, val, isLocal, ttl) / getStorage(prop, isLocal) / removeStorage(prop, isLocal) / getStorageKeys(isLocal)는 브라우저 환경에서는 sessionStorage/localStorage를 그대로 사용하고, Node(디바이스) 환경에서 세션 저장(isLocal이 아닌 경우)은 expiry/ttl 필드를 포함한 래퍼 객체를 localStorage에 저장해 만료(TTL) 관리를 흉내냅니다. 조회 시 만료 시간이 지나면 자동으로 삭제되고, 만료 전이면 조회할 때마다 expiry가 갱신됩니다.
syn.$w.setStorage('token', 'abcd1234'); // sessionStorage (브라우저)
syn.$w.setStorage('token', 'abcd1234', true); // localStorage
var token = syn.$w.getStorage('token');
var keys = syn.$w.getStorageKeys(); // 저장된 전체 키 목록
syn.$w.removeStorage('token');
거래(transaction) 실행 흐름
화면 모듈에는 아래와 같은 형태로 거래별 입력/출력 매핑을 선언합니다(예시는 이 페이지의 webforms.js에 이미 존재하는 GD01 선언입니다).
transaction: {
GD01: {
inputs: [{ type: 'Row', dataFieldID: 'MainForm' }],
outputs: [{ type: 'Form', dataFieldID: 'MainForm' }]
}
}
실행 흐름은 다음과 같습니다.
transactionAction(functionID 또는 transactConfig, options)를 호출하면 내부적으로tryAddFunction()으로 화면의 거래 목록에 등록하고,transaction(functionID, callback, options)을 실행합니다.transaction()은 화면 컨트롤(synControls)에서inputs매핑에 해당하는 값을 수집해 서버로 전송할 거래 객체(transactionObject()로 생성한 골격)를 구성합니다.- 서버 응답은
outputs매핑에 따라 화면 컨트롤에 자동으로 반영되고, 완료 후hook.afterTransaction(error, functionID, result, additionalData, correlationID)가 호출됩니다. - 화면 매핑 없이 값을 직접 지정해 호출하려면
transactionDirect(directObject, callback, options)를 사용합니다. 이 경우functionID,transactionID등 값을 직접 채워 넘깁니다. - 컨트롤 매핑 없이 요청/응답 원본 값만 다루려면
getterValue(functionID)/setterValue(functionID, responseData)를 사용합니다.
options에는 message, dynamic, authorize, commandType, returnType, transactionScope, transactionLog, endpoint 등의 공통 옵션이 병합되어 전달됩니다(모두 syn.js 소스에 정의된 기본값이며, 특정 업무 데이터 필드가 아닙니다).
개발 환경(syn.Config.Environment가 D로 시작)에서 화면마다 다른 API 서버로 직접 요청을 보내야 한다면 화면 스크립트의 config.domainAPIServer에 대상 서버 정보를 지정합니다. 지정하지 않으면 전역 설정인 syn.Config.DomainAPIServer가 사용되며, 운영 환경에서는 이 화면별 재정의가 적용되지 않습니다.
// 화면 모듈(webforms.js)
config: {
domainAPIServer: { /* 개발 전용 API 서버 접속 정보 */ }
}
자동 매핑 거래 실행과 점검(transactionExchange / inspectExchange)
화면마다 transaction: { functionID: { inputs, outputs } }를 일일이 선언하는 대신, 화면 저작 도구 등이 생성한 $this.config.pageMappings(colGroups/rowGroups/exchanges) 정의를 그대로 읽어 컨트롤 값을 주고받는 방식도 지원합니다.
colGroups: 기능(거래) 단위 정의. 각 항목은groupID(기능 ID)와 요청/응답에 사용할requestRowGroupSet/responseRowGroupSet(rowGroup ID 배열)을 가집니다.rowGroups: 데이터 컬렉션 정의.type이Single이면 단건(Row/Form),Multi이면 다건(List/Grid)이며mappingControls(컨트롤 ID 배열)를 가집니다.exchanges:{ [colGroupID]: { [rowGroupID]: { [controlID]: { input, output } } } }형태로 컨트롤과 서버 필드명을 연결합니다.
$this.config.pageMappings = {
colGroups: [{ groupID: 'GD01', requestRowGroupSet: ['SearchForm'], responseRowGroupSet: ['MainForm'] }],
rowGroups: [
{ groupID: 'SearchForm', type: 'Single', mappingControls: ['txtKeyword'] },
{ groupID: 'MainForm', type: 'Single', mappingControls: ['txtName', 'txtEmail'] }
],
exchanges: {
GD01: {
SearchForm: { txtKeyword: { input: 'Keyword' } },
MainForm: { txtName: { output: 'Name' }, txtEmail: { output: 'Email' } }
}
}
};
syn.$w.transactionExchange('GD01', { message: '조회 중...' });
Single 타입 rowGroup이 그리드 컨트롤(syn-datafield 대상이 그리드/차트)에 연결돼 있으면, 그리드에서 선택한 행 값을 요청으로 자동 사용합니다(목록에서 한 행을 고른 뒤 상세 조회하는 화면에 적합).
매핑 설정이 올바른지 코드를 실행하지 않고 미리 확인하려면 inspectExchange(colGroupID)로 점검 보고서를 출력합니다.
console.log(syn.$w.inspectExchange('GD01'));
// 기능 "GD01" 매핑 점검
// 요청 SearchForm (Single --> Row)
// txtKeyword --> Keyword
// 응답 MainForm (Single --> Form)
// txtName <-- Name
// txtEmail <-- Email
// dataMapInterface: Row|Form
매핑이 빠진 컨트롤은 (매핑 없음)으로 표시되므로, 화면이 비어 있는 문제를 진단할 때 syn-datafield 이름과 exchanges 설정 중 어느 쪽이 어긋났는지 빠르게 좁힐 수 있습니다.
동적 스크립트/스타일 로딩
loadScript(url, scriptID, callback)/loadStyle(url, styleID, callback): 외부<script>/<link>리소스를 중복 없이<head>에 추가합니다.getDynamicStyle(styleID)/addCssRule(rules, styleID)/removeCssRule(identifier, styleID): 런타임에<style>시트를 생성/조회하고 CSS 규칙을 추가·삭제합니다.pseudoStyle(elID, selector, cssText)/pseudoStyles(elID, styles): 지정한<style>엘리먼트의 내용을 selector/cssText 조합으로 통째로 교체합니다.
syn.$w.loadStyle('/sample/syn/style.css', 'demo-style');
syn.$w.addCssRule('.highlight { background: yellow; }', 'demo-style');
syn.$w.pseudoStyle('quick-style', '#target', 'color: red;');
IntersectionObserver 기반 지연 로딩
startIntersection(id, placeholder, loadMore, options)는 placeholder 엘리먼트가 뷰포트(또는 지정한 root)에 들어오면 loadMore(done) 콜백을 실행하는 무한 스크롤/지연 로딩 헬퍼입니다. done(true)를 호출하면 해당 관찰이 자동으로 종료됩니다.
syn.$w.startIntersection('list-scroll', '#loading-placeholder', function (done) {
// 추가 데이터 로드 로직
done(false); // 계속 관찰, true면 관찰 종료
}, { rootMargin: '100px' });
syn.$w.stopIntersection('list-scroll');
syn.$w.stopAllIntersections();
실전 예제 페이지
/sample/syn/webforms.html 예제에서 다음 항목을 실습할 수 있습니다.
- 속성: version
- 메서드: setStorage(), getStorage(), removeStorage(), getStorageKeys(), activeControl(), argumentsExtend(), contentLoaded(), getTriggerOptions(), triggerAction(), getControlModule(), tryAddFunction(), getterValue(), setterValue(), transactionAction(), transaction(), transactionDirect(), transactionObject(), scrollToTop(), scrollToElement(), setFavicon(), fileDownload(), sleep(), purge(), setServiceObject(), setServiceClientHeader(), xmlHttp(), xmlParser(), apiHttp(), loadScript(), loadStyle(), getDynamicStyle(), addCssRule(), removeCssRule(), pseudoStyle(), pseudoStyles(), fetchText(), fetchJson(), loadJson(), loadJsonAsync(), fetchImage(), startIntersection(), stopIntersection(), stopAllIntersections()
transactionExchange()/inspectExchange()는$this.config.pageMappings설정이 필요하며, 이 예제 페이지에는 해당 설정이 없어 별도로 시연하지 않습니다. 사용법은 위 "자동 매핑 거래 실행과 점검" 절과 API 참조를 확인하세요.
주의 사항
GD01행(거래 실행:transactionAction()/transaction(),transactionDirect())은 실제 HandStack 백엔드/거래 모듈이 연결되어 있어야 정상 동작합니다. 이 예제 페이지를 백엔드 없이 단독으로 열면 해당 항목은 오류 메시지가 표시되거나 빈 결과가 반환됩니다 — 이는 정상적인 동작이며 페이지 자체의 오류가 아닙니다.getterValue()/setterValue()는 네트워크 요청 없이 화면-거래 매핑 설정과 컨트롤 값만 다루므로 백엔드 없이도 동작을 확인할 수 있습니다. 다만 실제 서버 응답 형태(응답 필드 구조)는 백엔드 거래 정의에 따라 달라지므로 이 문서에서는 임의의 업무 필드를 제시하지 않습니다.Node(디바이스) 환경과 브라우저 환경에서setStorage/getStorage의 세션 스토리지 동작 방식(TTL 유무)이 다릅니다.purge(),triggerAction()데모는 화면 조작 편의를 위한 예시이며, 운영 화면에서는 컨트롤 생명주기와 이벤트 바인딩 규칙을 함께 고려해야 합니다.apiHttp()(webform)와httpFetch()(request 모듈,syn.$r)는 서로 다 른 모듈의 별개 기능입니다. 이름이 유사하니 혼동하지 않도록 주의합니다.transactionExchange()/inspectExchange()는$this.config.pageMappings정의가 있는 화면에서만 동작합니다. 정의가 없으면 경고 로그만 남기고 조용히 종료(inspectExchange는 빈 문자열 반환)됩니다.
관련 모듈
- API 상세는 아래 API 참조 섹션을 확인하세요.
API 참조
모듈 정보
| 항목 | 내용 |
|---|---|
| 전역 별칭 | syn.$w (원본: context.$webform) |
| 예제 페이지 | /sample/syn/webforms.html |
| 의존 모듈 | syn.$l(library, get/eventLog/addEvent 등), syn.$d(dimension, offset), syn.$o(object), syn.$s(string), syn.$b(browser, getIpAddress), syn.$a(array), syn.uicontrols.*(그리드/차트 등 컨트롤) |