Slate 사용자 입력과 상태 복원
Slate의 상호작용은 입력 위젯, 다른 위젯의 선택 상태와 이벤트로 구성합니다. Dropdown, 텍스트 입력과 Radio 같은 입력값을 질의나 함수에 연결하고, 차트나 표의 선택값도 사용할 수 있습니다.
입력 하나가 다음 입력의 선택지를 바꾸는 연결은 짧고 이해하기 쉽게 유지합니다. 여러 필터를 조정해야 한다면 필터 설정과 결과 조회를 분리하여 질의를 수동으로 두고 Update Data 버튼으로 실행하는 방식을 권장합니다. 그렇지 않으면 입력을 바꿀 때마다 후속 질의를 반복할 수 있습니다.
쓰기 질의는 반드시 수동으로 설정하고 명시적인 사용자 동작으로 제출합니다. 입력값이 바뀔 때마다 데이터를 저장하도록 두지 않습니다.
기본 선택값 초기화
기본값을 v_defaults 객체 변수로 모을 수 있습니다. 다음은 선택지와 표시값이 대응하는 구성의 예입니다.
{
"w_multiselectWidget_raw":["a","b"],
"w_multiselectWidget_display":["Alpha","Beta"],
"w_textInput":"default"
}
Multiselect 위젯에서는 selectedValues와 selectedDisplayValues를 모두 연결합니다. 해당 두 속성의 설정은 다음과 같습니다.
{
"selectedValues":"{{v_defaults.w_multiselectWidget_raw}}",
"selectedDisplayValues":"{{v_defaults.w_multiselectWidget_display}}"
}
w_textInput에도 해당 기본 문자열을 연결합니다. 값이 이전과 같으면 의존 그래프가 후속 노드를 다시 계산하지 않을 수 있으므로 초기화 버튼의 이벤트를 v_defaults.set에 연결하고 다음처럼 객체의 entropy를 바꿉니다.
const defaults = {{v_defaults}};
defaults.entropy = Math.random();
return defaults;
기본값 자체는 유지하면서 바뀐 객체값으로 위젯의 선택을 다시 초기화합니다. 제출 후 초기화에도 같은 패턴을 사용할 수 있습니다.
URL에 따른 기본값
다른 앱의 링크나 iframe에서 다른 기본값을 제공하려면 v_multiSelect_raw, v_multiSelect_display, v_textInput과 v_entropy처럼 입력을 분리하고 함수에서 같은 기본값 객체로 모읍니다.
URL에서 받은 값은 String이므로 배열 입력은 JSON 문자열에서 변환합니다. 변수 기본값으로 이미 배열을 제공한 경우는 그대로 사용합니다.
const raw = {{v_multiSelect_raw}};
const display = {{v_multiSelect_display}};
const defaults = {
w_multiselectWidget_raw: typeof raw === "string" ? JSON.parse(raw) : raw,
w_multiselectWidget_display: typeof display === "string" ? JSON.parse(display) : display,
w_textInput: {{v_textInput}},
entropy: {{v_entropy}}
};
return defaults;
필요한 초기화 때 v_entropy.set에 새로운 Math.random() 값을 반환하면 이 함수의 결과도 갱신됩니다. URL 값과 범위는 변수를 따릅니다.
프로젝트 폼 검증 예
다음은 프로젝트 제목, URL, Contact 이메일, 설명과 상태를 입력받는 예제 업무 규칙입니다. 모든 필드를 요구하고 신규 제목 및 기본 키 중복, 이메일 형식과 설명 길이를 검사합니다. Palantir의 모든 폼에 일률적으로 적용되는 규칙은 아닙니다.
중복 조회 q_searchDuplicateProject와 q_checkUniquePrimaryKey가 성공하여 각각 hits와 rows 배열을 제공한 뒤 사용합니다. i_newProjectToggle.selectedValue는 신규 작성 여부의 Boolean을 제공하는 입력입니다. 실제 Toggle 위젯을 사용하는 구성이라면 해당 참조를 on 속성으로 맞춥니다.
f_validateInputs 함수 본문입니다.
var inputs = {
Project_Title: {{i_projectTitle.text}},
Primary_URL: {{i_primaryUrl.text}},
Contact: {{i_contact.text}},
Project_Quote: {{i_projectQuote.text}},
Status: {{i_status.selectedValue}}
};
var isNewProject = {{i_newProjectToggle.selectedValue}};
var duplicateProjects = {{q_searchDuplicateProject.result.[0].hits}};
var keyMatches = {{q_checkUniquePrimaryKey.result.[0].rows}};
var uniqueTitle = duplicateProjects.length === 0;
var disable = false;
var messages = [];
var button_text = (isNewProject ? "Save " : "Update ") + (inputs.Project_Title || "");
if (isNewProject && !uniqueTitle) {
disable = true;
messages.push('Title must be unique. "' + inputs.Project_Title + '" already exists.');
}
if (isNewProject && keyMatches.length > 0) {
disable = true;
var existing = keyMatches[0];
messages.push('This title conflicts with an existing project. The project was created as "'
+ existing.primaryKey.project_id + '" and is now titled as "' + existing.columns.title + '"');
}
if (!(inputs.Project_Title && inputs.Contact && inputs.Primary_URL && inputs.Project_Quote && inputs.Status)) {
disable = true;
messages.push("Complete all required fields.");
}
const email_regex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (inputs.Contact && !email_regex.test(inputs.Contact)) {
disable = true;
messages.push('Enter a valid email for "Contact Email"');
}
if (inputs.Project_Quote && inputs.Project_Quote.length > 140) {
disable = true;
messages.push("'Project Quote' must be at most 140 characters.");
}
return { inputs, disable, messages, button_text };
설명 길이는 JavaScript String.length 기준으로 140까지 허용합니다. 이메일 검사는 이 예제의 형식 검사이며 실제 메일 소유를 확인하는 절차는 아닙니다.
제출 버튼의 disabled는 {{f_validateInputs.disable}}, 문구는 {{f_validateInputs.button_text}}에 연결합니다. 오류 표시는 다음과 같이 구성할 수 있습니다.
{{#each f_validateInputs.messages}}
<div class="pt-tag pt-intent-danger pt-minimal">{{this}}</div>
{{/each}}
필요하면 필드별 메시지나 invalid class를 반환하여 입력 옆에 표시합니다. 프런트엔드 안내와 실제 제출을 보호하는 액션 규칙 및 키 제약은 구분합니다.
여러 번 입력을 모으기
Repeating Container는 표시 중심의 구성입니다. 안에 입력 위젯을 넣을 수는 있지만 각 입력 인스턴스는 그 Container 안에 범위가 한정되므로 밖에서 모든 인스턴스를 직접 참조하는 입력 폼으로 사용할 수 없습니다.
대신 한 벌의 입력을 반복 사용하고 사용자가 저장할 때 선택을 배열에 추가할 수 있습니다. v_userSelections의 기본값을 []로 두고 w_saveSelection.click을 v_userSelections.set에 연결합니다.
const userSelections = {{v_userSelections}};
const newSelection = {
primaryCategory: {{w_primaryCategory.selectedValue}},
secondaryCategories: {{w_secondaryCategory.selectedValues}}
};
userSelections.push(newSelection);
return userSelections;
누적한 값을 HTML에 표시하고 개별 항목을 삭제하는 이벤트를 추가할 수 있습니다. 이벤트 체인은 짧게 유지합니다. 입력 위젯이 서로를 순환 참조하여 어느 필터의 변경이든 모든 필터를 다시 바꾸는 관계는 의존 그래프에 만들 수 없습니다.
공유 뷰
공유 뷰는 앱의 선택 상태와 구성을 저장한 URL입니다. 다른 사용자가 열면 저장한 값이 기본값보다 우선하고 후속 의존 관계가 그 상태로 초기화됩니다.
저장 대상은 홈 페이지의 위젯 상호작용 속성과 Local 변수입니다. Shared 변수는 저장하거나 복원하지 않습니다.
View 모드의 Actions > Get shareable view에서 URL을 만들 수 있습니다. 코드 흐름에서는 saveView, viewSaved와 loadView를 연결합니다.
| 조건 | 영향 |
|---|---|
| 홈 페이지 | 현재는 홈 페이지 상태만 저장하고 복원합니다. |
| 위젯/변수 이름 변경 | 이름에 연결된 저장값은 해당 이름이 사라지면 복원하지 않습니다. |
| 위젯 유형 변경 | 저장 당시와 유형이 다르면 그 위젯의 상태를 적용하지 않습니다. |
| 앱 버전 변경 | 같은 이름의 대상이 남아 있으면 다른 버전에서도 뷰를 사용할 수 있습니다. |
앱 재로드 후 사용자별 값을 관리하는 다른 경로는 User storage입니다. 상태 모델과 실행 순서는 의존 관계 설계를 함께 적용합니다.