Form CRUD - Employees » History » Revision 2
Revision 1 (Lê Sĩ Quý, 08/29/2025 06:18 PM) → Revision 2/4 (Lê Sĩ Quý, 08/29/2025 06:27 PM)
# Form CRUD - Employees
# Form List - Employees
{{TOC}}
## JSON Schema
``` javascript
{
"display": "form",
"components": [
{
"title": "<strong>New Employee</strong>",
"collapsible": false,
"key": "NewEmployee",
"type": "panel",
"label": "Panel",
"input": false,
"tableView": false,
"components": [
{
"label": "Employee ID",
"applyMaskOn": "change",
"tableView": true,
"protected": true,
"customDefaultValue": "value = `EMP${moment().unix().toString().slice(-7)}`;",
"validate": {
"required": true
},
"validateWhenHidden": false,
"key": "EmployeeID",
"type": "textfield",
"input": true
},
{
"label": "Title Of Courtesy",
"widget": "choicesjs",
"tableView": true,
"data": {
"values": [
{
"label": "Mr.",
"value": "Mr."
},
{
"label": "Ms.",
"value": "Ms."
},
{
"label": "Dr.",
"value": "Dr."
},
{
"label": "Mrs.",
"value": "Mrs."
}
]
},
"validate": {
"required": true
},
"validateWhenHidden": false,
"key": "TitleOfCourtesy",
"type": "select",
"input": true
},
{
"label": "Last Name",
"applyMaskOn": "change",
"tableView": true,
"validate": {
"required": true
},
"validateWhenHidden": false,
"key": "LastName",
"type": "textfield",
"input": true
},
{
"label": "First Name",
"applyMaskOn": "change",
"tableView": true,
"validate": {
"required": true
},
"validateWhenHidden": false,
"key": "FirstName",
"type": "textfield",
"input": true
},
{
"label": "Title",
"widget": "choicesjs",
"tableView": true,
"data": {
"values": [
{
"label": "Sales Manager",
"value": "Sales Manager"
},
{
"label": "Inside Sales Coordinator",
"value": "Inside Sales Coordinator"
},
{
"label": "Sales Representative",
"value": "Sales Representative"
},
{
"label": "Vice President, Sales",
"value": "Vice President, Sales"
}
]
},
"validateWhenHidden": false,
"key": "Title",
"type": "select",
"input": true
},
{
"label": "Birth Date",
"format": "yyyy-MM-dd",
"tableView": false,
"datePicker": {
"disableWeekends": false,
"disableWeekdays": false
},
"enableTime": false,
"validate": {
"required": true
},
"enableMinDateInput": false,
"enableMaxDateInput": false,
"validateWhenHidden": false,
"key": "BirthDate",
"type": "datetime",
"input": true,
"widget": {
"type": "calendar",
"displayInTimezone": "viewer",
"locale": "en",
"useLocaleSettings": false,
"allowInput": true,
"mode": "single",
"enableTime": false,
"noCalendar": false,
"format": "yyyy-MM-dd",
"hourIncrement": 1,
"minuteIncrement": 1,
"time_24hr": false,
"minDate": null,
"disableWeekends": false,
"disableWeekdays": false,
"maxDate": null
}
},
{
"label": "Hire Date",
"format": "yyyy-MM-dd",
"tableView": false,
"datePicker": {
"disableWeekends": false,
"disableWeekdays": false
},
"enableTime": false,
"validate": {
"required": true
},
"enableMinDateInput": false,
"enableMaxDateInput": false,
"validateWhenHidden": false,
"key": "HireDate",
"type": "datetime",
"input": true,
"widget": {
"type": "calendar",
"displayInTimezone": "viewer",
"locale": "en",
"useLocaleSettings": false,
"allowInput": true,
"mode": "single",
"enableTime": false,
"noCalendar": false,
"format": "yyyy-MM-dd",
"hourIncrement": 1,
"minuteIncrement": 1,
"time_24hr": false,
"minDate": null,
"disableWeekends": false,
"disableWeekdays": false,
"maxDate": null
}
},
{
"label": "Address",
"applyMaskOn": "change",
"tableView": true,
"validate": {
"required": true
},
"validateWhenHidden": false,
"key": "Address",
"type": "textfield",
"input": true
},
{
"label": "City",
"applyMaskOn": "change",
"tableView": true,
"validateWhenHidden": false,
"key": "City",
"type": "textfield",
"input": true
},
{
"label": "Region",
"applyMaskOn": "change",
"tableView": true,
"validateWhenHidden": false,
"key": "Region",
"type": "textfield",
"input": true
},
{
"label": "Postal Code",
"applyMaskOn": "change",
"tableView": true,
"validateWhenHidden": false,
"key": "PostalCode",
"type": "textfield",
"input": true
},
{
"label": "Country",
"widget": "choicesjs",
"tableView": true,
"dataSrc": "json",
"data": {
"json": [
{
"name": "Afghanistan",
"code": "AF"
},
{
"name": "Åland Islands",
"code": "AX"
},
{
"name": "Albania",
"code": "AL"
},
{
"name": "Algeria",
"code": "DZ"
},
{
"name": "American Samoa",
"code": "AS"
},
{
"name": "AndorrA",
"code": "AD"
},
{
"name": "Angola",
"code": "AO"
},
{
"name": "Anguilla",
"code": "AI"
},
{
"name": "Antarctica",
"code": "AQ"
},
{
"name": "Antigua and Barbuda",
"code": "AG"
},
{
"name": "Argentina",
"code": "AR"
},
{
"name": "Armenia",
"code": "AM"
},
{
"name": "Aruba",
"code": "AW"
},
{
"name": "Australia",
"code": "AU"
},
{
"name": "Austria",
"code": "AT"
},
{
"name": "Azerbaijan",
"code": "AZ"
},
{
"name": "Bahamas",
"code": "BS"
},
{
"name": "Bahrain",
"code": "BH"
},
{
"name": "Bangladesh",
"code": "BD"
},
{
"name": "Barbados",
"code": "BB"
},
{
"name": "Belarus",
"code": "BY"
},
{
"name": "Belgium",
"code": "BE"
},
{
"name": "Belize",
"code": "BZ"
},
{
"name": "Benin",
"code": "BJ"
},
{
"name": "Bermuda",
"code": "BM"
},
{
"name": "Bhutan",
"code": "BT"
},
{
"name": "Bolivia",
"code": "BO"
},
{
"name": "Bosnia and Herzegovina",
"code": "BA"
},
{
"name": "Botswana",
"code": "BW"
},
{
"name": "Bouvet Island",
"code": "BV"
},
{
"name": "Brazil",
"code": "BR"
},
{
"name": "British Indian Ocean Territory",
"code": "IO"
},
{
"name": "Brunei Darussalam",
"code": "BN"
},
{
"name": "Bulgaria",
"code": "BG"
},
{
"name": "Burkina Faso",
"code": "BF"
},
{
"name": "Burundi",
"code": "BI"
},
{
"name": "Cambodia",
"code": "KH"
},
{
"name": "Cameroon",
"code": "CM"
},
{
"name": "Canada",
"code": "CA"
},
{
"name": "Cape Verde",
"code": "CV"
},
{
"name": "Cayman Islands",
"code": "KY"
},
{
"name": "Central African Republic",
"code": "CF"
},
{
"name": "Chad",
"code": "TD"
},
{
"name": "Chile",
"code": "CL"
},
{
"name": "China",
"code": "CN"
},
{
"name": "Christmas Island",
"code": "CX"
},
{
"name": "Cocos (Keeling) Islands",
"code": "CC"
},
{
"name": "Colombia",
"code": "CO"
},
{
"name": "Comoros",
"code": "KM"
},
{
"name": "Congo",
"code": "CG"
},
{
"name": "Congo, The Democratic Republic of the",
"code": "CD"
},
{
"name": "Cook Islands",
"code": "CK"
},
{
"name": "Costa Rica",
"code": "CR"
},
{
"name": "Cote D\"Ivoire",
"code": "CI"
},
{
"name": "Croatia",
"code": "HR"
},
{
"name": "Cuba",
"code": "CU"
},
{
"name": "Cyprus",
"code": "CY"
},
{
"name": "Czech Republic",
"code": "CZ"
},
{
"name": "Denmark",
"code": "DK"
},
{
"name": "Djibouti",
"code": "DJ"
},
{
"name": "Dominica",
"code": "DM"
},
{
"name": "Dominican Republic",
"code": "DO"
},
{
"name": "Ecuador",
"code": "EC"
},
{
"name": "Egypt",
"code": "EG"
},
{
"name": "El Salvador",
"code": "SV"
},
{
"name": "Equatorial Guinea",
"code": "GQ"
},
{
"name": "Eritrea",
"code": "ER"
},
{
"name": "Estonia",
"code": "EE"
},
{
"name": "Ethiopia",
"code": "ET"
},
{
"name": "Falkland Islands (Malvinas)",
"code": "FK"
},
{
"name": "Faroe Islands",
"code": "FO"
},
{
"name": "Fiji",
"code": "FJ"
},
{
"name": "Finland",
"code": "FI"
},
{
"name": "France",
"code": "FR"
},
{
"name": "French Guiana",
"code": "GF"
},
{
"name": "French Polynesia",
"code": "PF"
},
{
"name": "French Southern Territories",
"code": "TF"
},
{
"name": "Gabon",
"code": "GA"
},
{
"name": "Gambia",
"code": "GM"
},
{
"name": "Georgia",
"code": "GE"
},
{
"name": "Germany",
"code": "DE"
},
{
"name": "Ghana",
"code": "GH"
},
{
"name": "Gibraltar",
"code": "GI"
},
{
"name": "Greece",
"code": "GR"
},
{
"name": "Greenland",
"code": "GL"
},
{
"name": "Grenada",
"code": "GD"
},
{
"name": "Guadeloupe",
"code": "GP"
},
{
"name": "Guam",
"code": "GU"
},
{
"name": "Guatemala",
"code": "GT"
},
{
"name": "Guernsey",
"code": "GG"
},
{
"name": "Guinea",
"code": "GN"
},
{
"name": "Guinea-Bissau",
"code": "GW"
},
{
"name": "Guyana",
"code": "GY"
},
{
"name": "Haiti",
"code": "HT"
},
{
"name": "Heard Island and Mcdonald Islands",
"code": "HM"
},
{
"name": "Holy See (Vatican City State)",
"code": "VA"
},
{
"name": "Honduras",
"code": "HN"
},
{
"name": "Hong Kong",
"code": "HK"
},
{
"name": "Hungary",
"code": "HU"
},
{
"name": "Iceland",
"code": "IS"
},
{
"name": "India",
"code": "IN"
},
{
"name": "Indonesia",
"code": "ID"
},
{
"name": "Iran, Islamic Republic Of",
"code": "IR"
},
{
"name": "Iraq",
"code": "IQ"
},
{
"name": "Ireland",
"code": "IE"
},
{
"name": "Isle of Man",
"code": "IM"
},
{
"name": "Israel",
"code": "IL"
},
{
"name": "Italy",
"code": "IT"
},
{
"name": "Jamaica",
"code": "JM"
},
{
"name": "Japan",
"code": "JP"
},
{
"name": "Jersey",
"code": "JE"
},
{
"name": "Jordan",
"code": "JO"
},
{
"name": "Kazakhstan",
"code": "KZ"
},
{
"name": "Kenya",
"code": "KE"
},
{
"name": "Kiribati",
"code": "KI"
},
{
"name": "Korea, Democratic People\"S Republic of",
"code": "KP"
},
{
"name": "Korea, Republic of",
"code": "KR"
},
{
"name": "Kuwait",
"code": "KW"
},
{
"name": "Kyrgyzstan",
"code": "KG"
},
{
"name": "Lao People\"S Democratic Republic",
"code": "LA"
},
{
"name": "Latvia",
"code": "LV"
},
{
"name": "Lebanon",
"code": "LB"
},
{
"name": "Lesotho",
"code": "LS"
},
{
"name": "Liberia",
"code": "LR"
},
{
"name": "Libyan Arab Jamahiriya",
"code": "LY"
},
{
"name": "Liechtenstein",
"code": "LI"
},
{
"name": "Lithuania",
"code": "LT"
},
{
"name": "Luxembourg",
"code": "LU"
},
{
"name": "Macao",
"code": "MO"
},
{
"name": "Macedonia, The Former Yugoslav Republic of",
"code": "MK"
},
{
"name": "Madagascar",
"code": "MG"
},
{
"name": "Malawi",
"code": "MW"
},
{
"name": "Malaysia",
"code": "MY"
},
{
"name": "Maldives",
"code": "MV"
},
{
"name": "Mali",
"code": "ML"
},
{
"name": "Malta",
"code": "MT"
},
{
"name": "Marshall Islands",
"code": "MH"
},
{
"name": "Martinique",
"code": "MQ"
},
{
"name": "Mauritania",
"code": "MR"
},
{
"name": "Mauritius",
"code": "MU"
},
{
"name": "Mayotte",
"code": "YT"
},
{
"name": "Mexico",
"code": "MX"
},
{
"name": "Micronesia, Federated States of",
"code": "FM"
},
{
"name": "Moldova, Republic of",
"code": "MD"
},
{
"name": "Monaco",
"code": "MC"
},
{
"name": "Mongolia",
"code": "MN"
},
{
"name": "Montserrat",
"code": "MS"
},
{
"name": "Morocco",
"code": "MA"
},
{
"name": "Mozambique",
"code": "MZ"
},
{
"name": "Myanmar",
"code": "MM"
},
{
"name": "Namibia",
"code": "NA"
},
{
"name": "Nauru",
"code": "NR"
},
{
"name": "Nepal",
"code": "NP"
},
{
"name": "Netherlands",
"code": "NL"
},
{
"name": "Netherlands Antilles",
"code": "AN"
},
{
"name": "New Caledonia",
"code": "NC"
},
{
"name": "New Zealand",
"code": "NZ"
},
{
"name": "Nicaragua",
"code": "NI"
},
{
"name": "Niger",
"code": "NE"
},
{
"name": "Nigeria",
"code": "NG"
},
{
"name": "Niue",
"code": "NU"
},
{
"name": "Norfolk Island",
"code": "NF"
},
{
"name": "Northern Mariana Islands",
"code": "MP"
},
{
"name": "Norway",
"code": "NO"
},
{
"name": "Oman",
"code": "OM"
},
{
"name": "Pakistan",
"code": "PK"
},
{
"name": "Palau",
"code": "PW"
},
{
"name": "Palestinian Territory, Occupied",
"code": "PS"
},
{
"name": "Panama",
"code": "PA"
},
{
"name": "Papua New Guinea",
"code": "PG"
},
{
"name": "Paraguay",
"code": "PY"
},
{
"name": "Peru",
"code": "PE"
},
{
"name": "Philippines",
"code": "PH"
},
{
"name": "Pitcairn",
"code": "PN"
},
{
"name": "Poland",
"code": "PL"
},
{
"name": "Portugal",
"code": "PT"
},
{
"name": "Puerto Rico",
"code": "PR"
},
{
"name": "Qatar",
"code": "QA"
},
{
"name": "Reunion",
"code": "RE"
},
{
"name": "Romania",
"code": "RO"
},
{
"name": "Russian Federation",
"code": "RU"
},
{
"name": "RWANDA",
"code": "RW"
},
{
"name": "Saint Helena",
"code": "SH"
},
{
"name": "Saint Kitts and Nevis",
"code": "KN"
},
{
"name": "Saint Lucia",
"code": "LC"
},
{
"name": "Saint Pierre and Miquelon",
"code": "PM"
},
{
"name": "Saint Vincent and the Grenadines",
"code": "VC"
},
{
"name": "Samoa",
"code": "WS"
},
{
"name": "San Marino",
"code": "SM"
},
{
"name": "Sao Tome and Principe",
"code": "ST"
},
{
"name": "Saudi Arabia",
"code": "SA"
},
{
"name": "Senegal",
"code": "SN"
},
{
"name": "Serbia and Montenegro",
"code": "CS"
},
{
"name": "Seychelles",
"code": "SC"
},
{
"name": "Sierra Leone",
"code": "SL"
},
{
"name": "Singapore",
"code": "SG"
},
{
"name": "Slovakia",
"code": "SK"
},
{
"name": "Slovenia",
"code": "SI"
},
{
"name": "Solomon Islands",
"code": "SB"
},
{
"name": "Somalia",
"code": "SO"
},
{
"name": "South Africa",
"code": "ZA"
},
{
"name": "South Georgia and the South Sandwich Islands",
"code": "GS"
},
{
"name": "Spain",
"code": "ES"
},
{
"name": "Sri Lanka",
"code": "LK"
},
{
"name": "Sudan",
"code": "SD"
},
{
"name": "Suriname",
"code": "SR"
},
{
"name": "Svalbard and Jan Mayen",
"code": "SJ"
},
{
"name": "Swaziland",
"code": "SZ"
},
{
"name": "Sweden",
"code": "SE"
},
{
"name": "Switzerland",
"code": "CH"
},
{
"name": "Syrian Arab Republic",
"code": "SY"
},
{
"name": "Taiwan",
"code": "TW"
},
{
"name": "Tajikistan",
"code": "TJ"
},
{
"name": "Tanzania, United Republic of",
"code": "TZ"
},
{
"name": "Thailand",
"code": "TH"
},
{
"name": "Timor-Leste",
"code": "TL"
},
{
"name": "Togo",
"code": "TG"
},
{
"name": "Tokelau",
"code": "TK"
},
{
"name": "Tonga",
"code": "TO"
},
{
"name": "Trinidad and Tobago",
"code": "TT"
},
{
"name": "Tunisia",
"code": "TN"
},
{
"name": "Turkey",
"code": "TR"
},
{
"name": "Turkmenistan",
"code": "TM"
},
{
"name": "Turks and Caicos Islands",
"code": "TC"
},
{
"name": "Tuvalu",
"code": "TV"
},
{
"name": "Uganda",
"code": "UG"
},
{
"name": "Ukraine",
"code": "UA"
},
{
"name": "United Arab Emirates",
"code": "AE"
},
{
"name": "United Kingdom",
"code": "GB"
},
{
"name": "United States",
"code": "US"
},
{
"name": "United States Minor Outlying Islands",
"code": "UM"
},
{
"name": "Uruguay",
"code": "UY"
},
{
"name": "Uzbekistan",
"code": "UZ"
},
{
"name": "Vanuatu",
"code": "VU"
},
{
"name": "Venezuela",
"code": "VE"
},
{
"name": "Viet Nam",
"code": "VN"
},
{
"name": "Virgin Islands, British",
"code": "VG"
},
{
"name": "Virgin Islands, U.S.",
"code": "VI"
},
{
"name": "Wallis and Futuna",
"code": "WF"
},
{
"name": "Western Sahara",
"code": "EH"
},
{
"name": "Yemen",
"code": "YE"
},
{
"name": "Zambia",
"code": "ZM"
},
{
"name": "Zimbabwe",
"code": "ZW"
}
]
},
"valueProperty": "name",
"template": "<span>{{ item.name }}</span>",
"validateWhenHidden": false,
"key": "Country",
"type": "select",
"input": true
},
{
"label": "Home Phone",
"applyMaskOn": "change",
"tableView": true,
"validateWhenHidden": false,
"key": "HomePhone",
"type": "phoneNumber",
"input": true
},
{
"label": "Extension",
"applyMaskOn": "change",
"mask": false,
"tableView": false,
"delimiter": false,
"requireDecimal": false,
"inputFormat": "plain",
"truncateMultipleSpaces": false,
"validateWhenHidden": false,
"key": "Extension",
"type": "number",
"input": true
},
{
"label": "Notes",
"applyMaskOn": "change",
"autoExpand": false,
"tableView": true,
"validateWhenHidden": false,
"key": "Notes",
"type": "textarea",
"input": true
},
{
"label": "ReportsTo",
"optionsLabelPosition": "right",
"inline": false,
"tableView": false,
"values": [
{
"label": " Buchanan, Steven",
"value": " Buchanan, Steven",
"shortcut": ""
},
{
"label": "Callahan, Laura",
"value": "Callahan, Laura",
"shortcut": ""
},
{
"label": "Davolio, Nancy",
"value": "Davolio, Nancy",
"shortcut": ""
},
{
"label": "Dodsworth, Anne",
"value": "Dodsworth, Anne",
"shortcut": ""
},
{
"label": "Fuller, Andrew",
"value": "Fuller, Andrew",
"shortcut": ""
},
{
"label": "King, Robert",
"value": "King, Robert",
"shortcut": ""
},
{
"label": "Leverling, Janet",
"value": "Leverling, Janet",
"shortcut": ""
},
{
"label": "Peacock, Margaret",
"value": "Peacock, Margaret",
"shortcut": ""
},
{
"label": "Suyama, Michael",
"value": "Suyama, Michael",
"shortcut": ""
}
],
"validateWhenHidden": false,
"key": "ReportsTo",
"type": "radio",
"input": true
}
]
},
{
"label": "Save",
"showValidations": false,
"disableOnInvalid": true,
"tableView": false,
"key": "submit",
"type": "button",
"saveOnEnter": false,
"input": true
}
]
}
```
## HTML Template
``` html
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport"
content="user-scalable=no, initial-scale=1.0001, maximum-scale=1.0001, width=device-width, minimal-ui shrink-to-fit=no">
<meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Northwind</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/awesome-notifications/3.1.0/style.min.css">
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/w2ui@2.0.0/w2ui-2.0.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/awesome-notifications/3.1.0/modern.var.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/localstorage-slim"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdn.form.io/js/formio.embed.js"></script>
</head>
<body>
<style>
button[type="submit"] {
background-color: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1em;
width: 100%;
}
</style>
<div id="toolbar"></div>
<div id="formio"></div>
<script type="module">
import { w2toolbar } from "https://cdn.jsdelivr.net/npm/w2ui@2.0.0/w2ui-2.0.es6.min.js";
var $ds = {};
var email = ls.get("email");
var notifier = new AWN({ option: "top-right" });
var sid = ls.get("sid");
$(function () {
if (sid) {
google.script.run
.withSuccessHandler(onCheckSidSuccess)
.withFailureHandler(onInvalidSid)
.checkSid(sid);
}
else {
onInvalidSid();
}
});
function onInvalidSid(err) {
if (err) {
notifier.warning(err.message);
}
else {
let url = "<?!= base ?>?url=/form/login&callback=<?!= url ?>";
notifier.modal(`<b>You need to login to access this page.</b><br><a href="${url}">👉 <b>Login</b></a>`)
}
}
function onCheckSidSuccess(valid) {
new w2toolbar({
box: "#toolbar",
name: "toolbar",
items: [
{
type: "menu", id: "sales", icon: "w2ui-icon-info", text: "Sales",
items: [
{ id: "customers", text: "Customers", icon: "fa fa-user" },
{ id: "orders", text: "Orders", icon: "fa fa-file-text" },
]
},
{ type: "break" },
{
type: "menu", id: "operations", icon: "w2ui-icon-settings", text: "Operations",
items: [
{ id: "employees", text: "Employees", icon: "fa fa-address-card" },
{ id: "products", text: "Products", icon: "fa fa-archive" },
{ id: "categories", text: "Product Categories", icon: "fa fa-sitemap" },
{ id: "suppliers", text: "Suppliers", icon: "fa fa-user" },
{ id: "shippers", text: "Shippers", icon: "fa fa-shopping-cart" }
]
},
{ type: "spacer" },
{
type: "menu", id: "auth", text: email,
items: [
{ text: "Logout", id: "logout", icon: "fa fa-sign-out" }
]
}
],
onClick(event) {
switch (event.target) {
case "sales:customers": {
window.open("<?= base ?>?url=/form/customers", "_top");
break;
}
case "sales:orders": {
window.open("<?= base ?>?url=/form/orders", "_top");
break;
}
case "operations:employees": {
window.open("<?= base ?>?url=/form/employees", "_top");
break;
}
case "operations:products": {
window.open("<?= base ?>?url=/form/products", "_top");
break;
}
case "operations:categories": {
window.open("<?= base ?>?url=/form/categories", "_top");
break;
}
case "operations:suppliers": {
window.open("<?= base ?>?url=/form/suppliers", "_top");
break;
}
case "operations:shippers": {
window.open("<?= base ?>?url=/form/shippers", "_top");
break;
}
case "auth:logout": {
ls.remove("sid");
ls.remove("email");
window.open("<?= base ?>?url=/form/login&callback=<?!= url ?>", "_top");
break;
}
}
}
});
if (valid) {
google.script.run.withSuccessHandler(showForms)
.loadDatasources("<?!= datasource ?>");
} else {
onInvalidSid();
}
}
function showForms(ds) {
$ds = ds;
let rec = <?!= (data) ?>;
Formio.createForm(document.getElementById("formio"), <?!= template ?>)
.then(function (form) {
// Prevent the submission from going to the form.io server.
form.noAlerts = true;
form.nosubmit = true;
form.submission = rec.Document ? { data: JSON.parse(rec.Document) } : {};
// Triggered when they click the submit button.
form.on("submit", function (submission) {
google.script.run
.withFailureHandler((err) => {
notifier.warning("Successfully saved.");
form.emit("submitError");
})
.withSuccessHandler((id) => {
if (!id) {
form.emit("submitError");
notifier.warning("An error occurred while saving the entry.");
}
else {
form.emit("submitDone");
<? if (!id) { ?>
form.submission = {};
form.refresh();
<? } ?>
notifier.success("Successfully saved.");
}
})
<? if (id) { ?>
.update("<?!= id ?>", "<?!= form.Id ?>", { Document: JSON.stringify(submission.data) }, null, sid)
<? } else { ?>
.create("<?!= form.Id ?>", { Document: JSON.stringify(submission.data) }, sid);
<? } ?>
});
});
}
</script>
</body>
</html>
```
## Giải thích Code
Form List Employees sử dụng cácthư viện sau:
- [jQuery](https://jquery.com/) để khởi tạo grid sau khi page load xong.
- [localstorage-slim](https://github.com/digitalfortress-tech/localstorage-slim) để đọc sid & email để bỏ qua bước login nếu trước đó đã login thành công. Trường hợp login không thành công thì sẽ thông báo và điều hướng đến trang login.
- [Notyf](https://carlosroso.com/notyf/) hiển thị thông báo.
- [w2ui](https://w2ui.com/web/home) cung cấp các thành phần UI cơ bản và nâng cao, ví dụ: toolbar và grid, dialog...
- Các thư viện đều được load từ CDN để tối ưu tốc độ, đơn giản hóa HTML Templated. Các bạn cần có kiến thức trong phần yêu cầu để hiểu logic của code JS + templated nhúng trong page.
- Trong page này gọi đến
- Hàm backend **checkSid** sid lưu trữ có khớp với giá trị trên server, nếu đúng thì sẽ sử dụng email trả về, còn sai sẽ điều hướng đến trang login
- Hàm backend **loadDatasources** để tải các dữ liệu tham chiếu phía client, ví dụ danh sách Products
- Hàm backend **create** để **runSql** thực hiện query nâng cao trên Datasource chỉ định, ví dụ chỉ hiển thị ra danh sách Orders được tạo bởi Saler đang login
*Vì Employee được lưu form submission dưới trong dạng document trong database với cơ chế NoSQL
- Hàm backend **update** để cập nhật record đã tồn tại với record id được truyền vào từ url theo định dạng **form-id/record-id**. Trong trường hợp này record-id chính là column Id with Google Forms nên chúng ta phải có bước tách các thuộc tính của document. Employee rồi mới thực hiện việc binding thay vì binding trực tiếp như Categories, Shippers*
``` javascript
let obj = JSON.parse(parent.Document);
```
## Demo
- Link: https://script.google.com/macros/s/AKfycbwIjB-hULVZdfCtsXFPg4Af_8WoKx2AFf85KMVwnsO_WkeAXW3zarT6vZNFVfwccz1_sA/exec?url=/form/employees
- Account: user@northwind.com
- Password: user