Project

General

Profile

Form CRUD - Employees » History » Version 4

Lê Sĩ Quý, 08/29/2025 06:28 PM

1 1 Lê Sĩ Quý
# Form CRUD - Employees
2
3
{{TOC}}
4
5
## JSON Schema
6
7
``` javascript
8
{
9
  "display": "form",
10
  "components": [
11
    {
12
      "title": "<strong>New Employee</strong>",
13
      "collapsible": false,
14
      "key": "NewEmployee",
15
      "type": "panel",
16
      "label": "Panel",
17
      "input": false,
18
      "tableView": false,
19
      "components": [
20
        {
21
          "label": "Employee ID",
22
          "applyMaskOn": "change",
23
          "tableView": true,
24
          "protected": true,
25
          "customDefaultValue": "value = `EMP${moment().unix().toString().slice(-7)}`;",
26
          "validate": {
27
            "required": true
28
          },
29
          "validateWhenHidden": false,
30
          "key": "EmployeeID",
31
          "type": "textfield",
32
          "input": true
33
        },
34
        {
35
          "label": "Title Of Courtesy",
36
          "widget": "choicesjs",
37
          "tableView": true,
38
          "data": {
39
            "values": [
40
              {
41
                "label": "Mr.",
42
                "value": "Mr."
43
              },
44
              {
45
                "label": "Ms.",
46
                "value": "Ms."
47
              },
48
              {
49
                "label": "Dr.",
50
                "value": "Dr."
51
              },
52
              {
53
                "label": "Mrs.",
54
                "value": "Mrs."
55
              }
56
            ]
57
          },
58
          "validate": {
59
            "required": true
60
          },
61
          "validateWhenHidden": false,
62
          "key": "TitleOfCourtesy",
63
          "type": "select",
64
          "input": true
65
        },
66
        {
67
          "label": "Last Name",
68
          "applyMaskOn": "change",
69
          "tableView": true,
70
          "validate": {
71
            "required": true
72
          },
73
          "validateWhenHidden": false,
74
          "key": "LastName",
75
          "type": "textfield",
76
          "input": true
77
        },
78
        {
79
          "label": "First Name",
80
          "applyMaskOn": "change",
81
          "tableView": true,
82
          "validate": {
83
            "required": true
84
          },
85
          "validateWhenHidden": false,
86
          "key": "FirstName",
87
          "type": "textfield",
88
          "input": true
89
        },
90
        {
91
          "label": "Title",
92
          "widget": "choicesjs",
93
          "tableView": true,
94
          "data": {
95
            "values": [
96
              {
97
                "label": "Sales Manager",
98
                "value": "Sales Manager"
99
              },
100
              {
101
                "label": "Inside Sales Coordinator",
102
                "value": "Inside Sales Coordinator"
103
              },
104
              {
105
                "label": "Sales Representative",
106
                "value": "Sales Representative"
107
              },
108
              {
109
                "label": "Vice President, Sales",
110
                "value": "Vice President, Sales"
111
              }
112
            ]
113
          },
114
          "validateWhenHidden": false,
115
          "key": "Title",
116
          "type": "select",
117
          "input": true
118
        },
119
        {
120
          "label": "Birth Date",
121
          "format": "yyyy-MM-dd",
122
          "tableView": false,
123
          "datePicker": {
124
            "disableWeekends": false,
125
            "disableWeekdays": false
126
          },
127
          "enableTime": false,
128
          "validate": {
129
            "required": true
130
          },
131
          "enableMinDateInput": false,
132
          "enableMaxDateInput": false,
133
          "validateWhenHidden": false,
134
          "key": "BirthDate",
135
          "type": "datetime",
136
          "input": true,
137
          "widget": {
138
            "type": "calendar",
139
            "displayInTimezone": "viewer",
140
            "locale": "en",
141
            "useLocaleSettings": false,
142
            "allowInput": true,
143
            "mode": "single",
144
            "enableTime": false,
145
            "noCalendar": false,
146
            "format": "yyyy-MM-dd",
147
            "hourIncrement": 1,
148
            "minuteIncrement": 1,
149
            "time_24hr": false,
150
            "minDate": null,
151
            "disableWeekends": false,
152
            "disableWeekdays": false,
153
            "maxDate": null
154
          }
155
        },
156
        {
157
          "label": "Hire Date",
158
          "format": "yyyy-MM-dd",
159
          "tableView": false,
160
          "datePicker": {
161
            "disableWeekends": false,
162
            "disableWeekdays": false
163
          },
164
          "enableTime": false,
165
          "validate": {
166
            "required": true
167
          },
168
          "enableMinDateInput": false,
169
          "enableMaxDateInput": false,
170
          "validateWhenHidden": false,
171
          "key": "HireDate",
172
          "type": "datetime",
173
          "input": true,
174
          "widget": {
175
            "type": "calendar",
176
            "displayInTimezone": "viewer",
177
            "locale": "en",
178
            "useLocaleSettings": false,
179
            "allowInput": true,
180
            "mode": "single",
181
            "enableTime": false,
182
            "noCalendar": false,
183
            "format": "yyyy-MM-dd",
184
            "hourIncrement": 1,
185
            "minuteIncrement": 1,
186
            "time_24hr": false,
187
            "minDate": null,
188
            "disableWeekends": false,
189
            "disableWeekdays": false,
190
            "maxDate": null
191
          }
192
        },
193
        {
194
          "label": "Address",
195
          "applyMaskOn": "change",
196
          "tableView": true,
197
          "validate": {
198
            "required": true
199
          },
200
          "validateWhenHidden": false,
201
          "key": "Address",
202
          "type": "textfield",
203
          "input": true
204
        },
205
        {
206
          "label": "City",
207
          "applyMaskOn": "change",
208
          "tableView": true,
209
          "validateWhenHidden": false,
210
          "key": "City",
211
          "type": "textfield",
212
          "input": true
213
        },
214
        {
215
          "label": "Region",
216
          "applyMaskOn": "change",
217
          "tableView": true,
218
          "validateWhenHidden": false,
219
          "key": "Region",
220
          "type": "textfield",
221
          "input": true
222
        },
223
        {
224
          "label": "Postal Code",
225
          "applyMaskOn": "change",
226
          "tableView": true,
227
          "validateWhenHidden": false,
228
          "key": "PostalCode",
229
          "type": "textfield",
230
          "input": true
231
        },
232
        {
233
          "label": "Country",
234
          "widget": "choicesjs",
235
          "tableView": true,
236
          "dataSrc": "json",
237
          "data": {
238
            "json": [
239
              {
240
                "name": "Afghanistan",
241
                "code": "AF"
242
              },
243
              {
244
                "name": "Åland Islands",
245
                "code": "AX"
246
              },
247
              {
248
                "name": "Albania",
249
                "code": "AL"
250
              },
251
              {
252
                "name": "Algeria",
253
                "code": "DZ"
254
              },
255
              {
256
                "name": "American Samoa",
257
                "code": "AS"
258
              },
259
              {
260
                "name": "AndorrA",
261
                "code": "AD"
262
              },
263
              {
264
                "name": "Angola",
265
                "code": "AO"
266
              },
267
              {
268
                "name": "Anguilla",
269
                "code": "AI"
270
              },
271
              {
272
                "name": "Antarctica",
273
                "code": "AQ"
274
              },
275
              {
276
                "name": "Antigua and Barbuda",
277
                "code": "AG"
278
              },
279
              {
280
                "name": "Argentina",
281
                "code": "AR"
282
              },
283
              {
284
                "name": "Armenia",
285
                "code": "AM"
286
              },
287
              {
288
                "name": "Aruba",
289
                "code": "AW"
290
              },
291
              {
292
                "name": "Australia",
293
                "code": "AU"
294
              },
295
              {
296
                "name": "Austria",
297
                "code": "AT"
298
              },
299
              {
300
                "name": "Azerbaijan",
301
                "code": "AZ"
302
              },
303
              {
304
                "name": "Bahamas",
305
                "code": "BS"
306
              },
307
              {
308
                "name": "Bahrain",
309
                "code": "BH"
310
              },
311
              {
312
                "name": "Bangladesh",
313
                "code": "BD"
314
              },
315
              {
316
                "name": "Barbados",
317
                "code": "BB"
318
              },
319
              {
320
                "name": "Belarus",
321
                "code": "BY"
322
              },
323
              {
324
                "name": "Belgium",
325
                "code": "BE"
326
              },
327
              {
328
                "name": "Belize",
329
                "code": "BZ"
330
              },
331
              {
332
                "name": "Benin",
333
                "code": "BJ"
334
              },
335
              {
336
                "name": "Bermuda",
337
                "code": "BM"
338
              },
339
              {
340
                "name": "Bhutan",
341
                "code": "BT"
342
              },
343
              {
344
                "name": "Bolivia",
345
                "code": "BO"
346
              },
347
              {
348
                "name": "Bosnia and Herzegovina",
349
                "code": "BA"
350
              },
351
              {
352
                "name": "Botswana",
353
                "code": "BW"
354
              },
355
              {
356
                "name": "Bouvet Island",
357
                "code": "BV"
358
              },
359
              {
360
                "name": "Brazil",
361
                "code": "BR"
362
              },
363
              {
364
                "name": "British Indian Ocean Territory",
365
                "code": "IO"
366
              },
367
              {
368
                "name": "Brunei Darussalam",
369
                "code": "BN"
370
              },
371
              {
372
                "name": "Bulgaria",
373
                "code": "BG"
374
              },
375
              {
376
                "name": "Burkina Faso",
377
                "code": "BF"
378
              },
379
              {
380
                "name": "Burundi",
381
                "code": "BI"
382
              },
383
              {
384
                "name": "Cambodia",
385
                "code": "KH"
386
              },
387
              {
388
                "name": "Cameroon",
389
                "code": "CM"
390
              },
391
              {
392
                "name": "Canada",
393
                "code": "CA"
394
              },
395
              {
396
                "name": "Cape Verde",
397
                "code": "CV"
398
              },
399
              {
400
                "name": "Cayman Islands",
401
                "code": "KY"
402
              },
403
              {
404
                "name": "Central African Republic",
405
                "code": "CF"
406
              },
407
              {
408
                "name": "Chad",
409
                "code": "TD"
410
              },
411
              {
412
                "name": "Chile",
413
                "code": "CL"
414
              },
415
              {
416
                "name": "China",
417
                "code": "CN"
418
              },
419
              {
420
                "name": "Christmas Island",
421
                "code": "CX"
422
              },
423
              {
424
                "name": "Cocos (Keeling) Islands",
425
                "code": "CC"
426
              },
427
              {
428
                "name": "Colombia",
429
                "code": "CO"
430
              },
431
              {
432
                "name": "Comoros",
433
                "code": "KM"
434
              },
435
              {
436
                "name": "Congo",
437
                "code": "CG"
438
              },
439
              {
440
                "name": "Congo, The Democratic Republic of the",
441
                "code": "CD"
442
              },
443
              {
444
                "name": "Cook Islands",
445
                "code": "CK"
446
              },
447
              {
448
                "name": "Costa Rica",
449
                "code": "CR"
450
              },
451
              {
452
                "name": "Cote D\"Ivoire",
453
                "code": "CI"
454
              },
455
              {
456
                "name": "Croatia",
457
                "code": "HR"
458
              },
459
              {
460
                "name": "Cuba",
461
                "code": "CU"
462
              },
463
              {
464
                "name": "Cyprus",
465
                "code": "CY"
466
              },
467
              {
468
                "name": "Czech Republic",
469
                "code": "CZ"
470
              },
471
              {
472
                "name": "Denmark",
473
                "code": "DK"
474
              },
475
              {
476
                "name": "Djibouti",
477
                "code": "DJ"
478
              },
479
              {
480
                "name": "Dominica",
481
                "code": "DM"
482
              },
483
              {
484
                "name": "Dominican Republic",
485
                "code": "DO"
486
              },
487
              {
488
                "name": "Ecuador",
489
                "code": "EC"
490
              },
491
              {
492
                "name": "Egypt",
493
                "code": "EG"
494
              },
495
              {
496
                "name": "El Salvador",
497
                "code": "SV"
498
              },
499
              {
500
                "name": "Equatorial Guinea",
501
                "code": "GQ"
502
              },
503
              {
504
                "name": "Eritrea",
505
                "code": "ER"
506
              },
507
              {
508
                "name": "Estonia",
509
                "code": "EE"
510
              },
511
              {
512
                "name": "Ethiopia",
513
                "code": "ET"
514
              },
515
              {
516
                "name": "Falkland Islands (Malvinas)",
517
                "code": "FK"
518
              },
519
              {
520
                "name": "Faroe Islands",
521
                "code": "FO"
522
              },
523
              {
524
                "name": "Fiji",
525
                "code": "FJ"
526
              },
527
              {
528
                "name": "Finland",
529
                "code": "FI"
530
              },
531
              {
532
                "name": "France",
533
                "code": "FR"
534
              },
535
              {
536
                "name": "French Guiana",
537
                "code": "GF"
538
              },
539
              {
540
                "name": "French Polynesia",
541
                "code": "PF"
542
              },
543
              {
544
                "name": "French Southern Territories",
545
                "code": "TF"
546
              },
547
              {
548
                "name": "Gabon",
549
                "code": "GA"
550
              },
551
              {
552
                "name": "Gambia",
553
                "code": "GM"
554
              },
555
              {
556
                "name": "Georgia",
557
                "code": "GE"
558
              },
559
              {
560
                "name": "Germany",
561
                "code": "DE"
562
              },
563
              {
564
                "name": "Ghana",
565
                "code": "GH"
566
              },
567
              {
568
                "name": "Gibraltar",
569
                "code": "GI"
570
              },
571
              {
572
                "name": "Greece",
573
                "code": "GR"
574
              },
575
              {
576
                "name": "Greenland",
577
                "code": "GL"
578
              },
579
              {
580
                "name": "Grenada",
581
                "code": "GD"
582
              },
583
              {
584
                "name": "Guadeloupe",
585
                "code": "GP"
586
              },
587
              {
588
                "name": "Guam",
589
                "code": "GU"
590
              },
591
              {
592
                "name": "Guatemala",
593
                "code": "GT"
594
              },
595
              {
596
                "name": "Guernsey",
597
                "code": "GG"
598
              },
599
              {
600
                "name": "Guinea",
601
                "code": "GN"
602
              },
603
              {
604
                "name": "Guinea-Bissau",
605
                "code": "GW"
606
              },
607
              {
608
                "name": "Guyana",
609
                "code": "GY"
610
              },
611
              {
612
                "name": "Haiti",
613
                "code": "HT"
614
              },
615
              {
616
                "name": "Heard Island and Mcdonald Islands",
617
                "code": "HM"
618
              },
619
              {
620
                "name": "Holy See (Vatican City State)",
621
                "code": "VA"
622
              },
623
              {
624
                "name": "Honduras",
625
                "code": "HN"
626
              },
627
              {
628
                "name": "Hong Kong",
629
                "code": "HK"
630
              },
631
              {
632
                "name": "Hungary",
633
                "code": "HU"
634
              },
635
              {
636
                "name": "Iceland",
637
                "code": "IS"
638
              },
639
              {
640
                "name": "India",
641
                "code": "IN"
642
              },
643
              {
644
                "name": "Indonesia",
645
                "code": "ID"
646
              },
647
              {
648
                "name": "Iran, Islamic Republic Of",
649
                "code": "IR"
650
              },
651
              {
652
                "name": "Iraq",
653
                "code": "IQ"
654
              },
655
              {
656
                "name": "Ireland",
657
                "code": "IE"
658
              },
659
              {
660
                "name": "Isle of Man",
661
                "code": "IM"
662
              },
663
              {
664
                "name": "Israel",
665
                "code": "IL"
666
              },
667
              {
668
                "name": "Italy",
669
                "code": "IT"
670
              },
671
              {
672
                "name": "Jamaica",
673
                "code": "JM"
674
              },
675
              {
676
                "name": "Japan",
677
                "code": "JP"
678
              },
679
              {
680
                "name": "Jersey",
681
                "code": "JE"
682
              },
683
              {
684
                "name": "Jordan",
685
                "code": "JO"
686
              },
687
              {
688
                "name": "Kazakhstan",
689
                "code": "KZ"
690
              },
691
              {
692
                "name": "Kenya",
693
                "code": "KE"
694
              },
695
              {
696
                "name": "Kiribati",
697
                "code": "KI"
698
              },
699
              {
700
                "name": "Korea, Democratic People\"S Republic of",
701
                "code": "KP"
702
              },
703
              {
704
                "name": "Korea, Republic of",
705
                "code": "KR"
706
              },
707
              {
708
                "name": "Kuwait",
709
                "code": "KW"
710
              },
711
              {
712
                "name": "Kyrgyzstan",
713
                "code": "KG"
714
              },
715
              {
716
                "name": "Lao People\"S Democratic Republic",
717
                "code": "LA"
718
              },
719
              {
720
                "name": "Latvia",
721
                "code": "LV"
722
              },
723
              {
724
                "name": "Lebanon",
725
                "code": "LB"
726
              },
727
              {
728
                "name": "Lesotho",
729
                "code": "LS"
730
              },
731
              {
732
                "name": "Liberia",
733
                "code": "LR"
734
              },
735
              {
736
                "name": "Libyan Arab Jamahiriya",
737
                "code": "LY"
738
              },
739
              {
740
                "name": "Liechtenstein",
741
                "code": "LI"
742
              },
743
              {
744
                "name": "Lithuania",
745
                "code": "LT"
746
              },
747
              {
748
                "name": "Luxembourg",
749
                "code": "LU"
750
              },
751
              {
752
                "name": "Macao",
753
                "code": "MO"
754
              },
755
              {
756
                "name": "Macedonia, The Former Yugoslav Republic of",
757
                "code": "MK"
758
              },
759
              {
760
                "name": "Madagascar",
761
                "code": "MG"
762
              },
763
              {
764
                "name": "Malawi",
765
                "code": "MW"
766
              },
767
              {
768
                "name": "Malaysia",
769
                "code": "MY"
770
              },
771
              {
772
                "name": "Maldives",
773
                "code": "MV"
774
              },
775
              {
776
                "name": "Mali",
777
                "code": "ML"
778
              },
779
              {
780
                "name": "Malta",
781
                "code": "MT"
782
              },
783
              {
784
                "name": "Marshall Islands",
785
                "code": "MH"
786
              },
787
              {
788
                "name": "Martinique",
789
                "code": "MQ"
790
              },
791
              {
792
                "name": "Mauritania",
793
                "code": "MR"
794
              },
795
              {
796
                "name": "Mauritius",
797
                "code": "MU"
798
              },
799
              {
800
                "name": "Mayotte",
801
                "code": "YT"
802
              },
803
              {
804
                "name": "Mexico",
805
                "code": "MX"
806
              },
807
              {
808
                "name": "Micronesia, Federated States of",
809
                "code": "FM"
810
              },
811
              {
812
                "name": "Moldova, Republic of",
813
                "code": "MD"
814
              },
815
              {
816
                "name": "Monaco",
817
                "code": "MC"
818
              },
819
              {
820
                "name": "Mongolia",
821
                "code": "MN"
822
              },
823
              {
824
                "name": "Montserrat",
825
                "code": "MS"
826
              },
827
              {
828
                "name": "Morocco",
829
                "code": "MA"
830
              },
831
              {
832
                "name": "Mozambique",
833
                "code": "MZ"
834
              },
835
              {
836
                "name": "Myanmar",
837
                "code": "MM"
838
              },
839
              {
840
                "name": "Namibia",
841
                "code": "NA"
842
              },
843
              {
844
                "name": "Nauru",
845
                "code": "NR"
846
              },
847
              {
848
                "name": "Nepal",
849
                "code": "NP"
850
              },
851
              {
852
                "name": "Netherlands",
853
                "code": "NL"
854
              },
855
              {
856
                "name": "Netherlands Antilles",
857
                "code": "AN"
858
              },
859
              {
860
                "name": "New Caledonia",
861
                "code": "NC"
862
              },
863
              {
864
                "name": "New Zealand",
865
                "code": "NZ"
866
              },
867
              {
868
                "name": "Nicaragua",
869
                "code": "NI"
870
              },
871
              {
872
                "name": "Niger",
873
                "code": "NE"
874
              },
875
              {
876
                "name": "Nigeria",
877
                "code": "NG"
878
              },
879
              {
880
                "name": "Niue",
881
                "code": "NU"
882
              },
883
              {
884
                "name": "Norfolk Island",
885
                "code": "NF"
886
              },
887
              {
888
                "name": "Northern Mariana Islands",
889
                "code": "MP"
890
              },
891
              {
892
                "name": "Norway",
893
                "code": "NO"
894
              },
895
              {
896
                "name": "Oman",
897
                "code": "OM"
898
              },
899
              {
900
                "name": "Pakistan",
901
                "code": "PK"
902
              },
903
              {
904
                "name": "Palau",
905
                "code": "PW"
906
              },
907
              {
908
                "name": "Palestinian Territory, Occupied",
909
                "code": "PS"
910
              },
911
              {
912
                "name": "Panama",
913
                "code": "PA"
914
              },
915
              {
916
                "name": "Papua New Guinea",
917
                "code": "PG"
918
              },
919
              {
920
                "name": "Paraguay",
921
                "code": "PY"
922
              },
923
              {
924
                "name": "Peru",
925
                "code": "PE"
926
              },
927
              {
928
                "name": "Philippines",
929
                "code": "PH"
930
              },
931
              {
932
                "name": "Pitcairn",
933
                "code": "PN"
934
              },
935
              {
936
                "name": "Poland",
937
                "code": "PL"
938
              },
939
              {
940
                "name": "Portugal",
941
                "code": "PT"
942
              },
943
              {
944
                "name": "Puerto Rico",
945
                "code": "PR"
946
              },
947
              {
948
                "name": "Qatar",
949
                "code": "QA"
950
              },
951
              {
952
                "name": "Reunion",
953
                "code": "RE"
954
              },
955
              {
956
                "name": "Romania",
957
                "code": "RO"
958
              },
959
              {
960
                "name": "Russian Federation",
961
                "code": "RU"
962
              },
963
              {
964
                "name": "RWANDA",
965
                "code": "RW"
966
              },
967
              {
968
                "name": "Saint Helena",
969
                "code": "SH"
970
              },
971
              {
972
                "name": "Saint Kitts and Nevis",
973
                "code": "KN"
974
              },
975
              {
976
                "name": "Saint Lucia",
977
                "code": "LC"
978
              },
979
              {
980
                "name": "Saint Pierre and Miquelon",
981
                "code": "PM"
982
              },
983
              {
984
                "name": "Saint Vincent and the Grenadines",
985
                "code": "VC"
986
              },
987
              {
988
                "name": "Samoa",
989
                "code": "WS"
990
              },
991
              {
992
                "name": "San Marino",
993
                "code": "SM"
994
              },
995
              {
996
                "name": "Sao Tome and Principe",
997
                "code": "ST"
998
              },
999
              {
1000
                "name": "Saudi Arabia",
1001
                "code": "SA"
1002
              },
1003
              {
1004
                "name": "Senegal",
1005
                "code": "SN"
1006
              },
1007
              {
1008
                "name": "Serbia and Montenegro",
1009
                "code": "CS"
1010
              },
1011
              {
1012
                "name": "Seychelles",
1013
                "code": "SC"
1014
              },
1015
              {
1016
                "name": "Sierra Leone",
1017
                "code": "SL"
1018
              },
1019
              {
1020
                "name": "Singapore",
1021
                "code": "SG"
1022
              },
1023
              {
1024
                "name": "Slovakia",
1025
                "code": "SK"
1026
              },
1027
              {
1028
                "name": "Slovenia",
1029
                "code": "SI"
1030
              },
1031
              {
1032
                "name": "Solomon Islands",
1033
                "code": "SB"
1034
              },
1035
              {
1036
                "name": "Somalia",
1037
                "code": "SO"
1038
              },
1039
              {
1040
                "name": "South Africa",
1041
                "code": "ZA"
1042
              },
1043
              {
1044
                "name": "South Georgia and the South Sandwich Islands",
1045
                "code": "GS"
1046
              },
1047
              {
1048
                "name": "Spain",
1049
                "code": "ES"
1050
              },
1051
              {
1052
                "name": "Sri Lanka",
1053
                "code": "LK"
1054
              },
1055
              {
1056
                "name": "Sudan",
1057
                "code": "SD"
1058
              },
1059
              {
1060
                "name": "Suriname",
1061
                "code": "SR"
1062
              },
1063
              {
1064
                "name": "Svalbard and Jan Mayen",
1065
                "code": "SJ"
1066
              },
1067
              {
1068
                "name": "Swaziland",
1069
                "code": "SZ"
1070
              },
1071
              {
1072
                "name": "Sweden",
1073
                "code": "SE"
1074
              },
1075
              {
1076
                "name": "Switzerland",
1077
                "code": "CH"
1078
              },
1079
              {
1080
                "name": "Syrian Arab Republic",
1081
                "code": "SY"
1082
              },
1083
              {
1084
                "name": "Taiwan",
1085
                "code": "TW"
1086
              },
1087
              {
1088
                "name": "Tajikistan",
1089
                "code": "TJ"
1090
              },
1091
              {
1092
                "name": "Tanzania, United Republic of",
1093
                "code": "TZ"
1094
              },
1095
              {
1096
                "name": "Thailand",
1097
                "code": "TH"
1098
              },
1099
              {
1100
                "name": "Timor-Leste",
1101
                "code": "TL"
1102
              },
1103
              {
1104
                "name": "Togo",
1105
                "code": "TG"
1106
              },
1107
              {
1108
                "name": "Tokelau",
1109
                "code": "TK"
1110
              },
1111
              {
1112
                "name": "Tonga",
1113
                "code": "TO"
1114
              },
1115
              {
1116
                "name": "Trinidad and Tobago",
1117
                "code": "TT"
1118
              },
1119
              {
1120
                "name": "Tunisia",
1121
                "code": "TN"
1122
              },
1123
              {
1124
                "name": "Turkey",
1125
                "code": "TR"
1126
              },
1127
              {
1128
                "name": "Turkmenistan",
1129
                "code": "TM"
1130
              },
1131
              {
1132
                "name": "Turks and Caicos Islands",
1133
                "code": "TC"
1134
              },
1135
              {
1136
                "name": "Tuvalu",
1137
                "code": "TV"
1138
              },
1139
              {
1140
                "name": "Uganda",
1141
                "code": "UG"
1142
              },
1143
              {
1144
                "name": "Ukraine",
1145
                "code": "UA"
1146
              },
1147
              {
1148
                "name": "United Arab Emirates",
1149
                "code": "AE"
1150
              },
1151
              {
1152
                "name": "United Kingdom",
1153
                "code": "GB"
1154
              },
1155
              {
1156
                "name": "United States",
1157
                "code": "US"
1158
              },
1159
              {
1160
                "name": "United States Minor Outlying Islands",
1161
                "code": "UM"
1162
              },
1163
              {
1164
                "name": "Uruguay",
1165
                "code": "UY"
1166
              },
1167
              {
1168
                "name": "Uzbekistan",
1169
                "code": "UZ"
1170
              },
1171
              {
1172
                "name": "Vanuatu",
1173
                "code": "VU"
1174
              },
1175
              {
1176
                "name": "Venezuela",
1177
                "code": "VE"
1178
              },
1179
              {
1180
                "name": "Viet Nam",
1181
                "code": "VN"
1182
              },
1183
              {
1184
                "name": "Virgin Islands, British",
1185
                "code": "VG"
1186
              },
1187
              {
1188
                "name": "Virgin Islands, U.S.",
1189
                "code": "VI"
1190
              },
1191
              {
1192
                "name": "Wallis and Futuna",
1193
                "code": "WF"
1194
              },
1195
              {
1196
                "name": "Western Sahara",
1197
                "code": "EH"
1198
              },
1199
              {
1200
                "name": "Yemen",
1201
                "code": "YE"
1202
              },
1203
              {
1204
                "name": "Zambia",
1205
                "code": "ZM"
1206
              },
1207
              {
1208
                "name": "Zimbabwe",
1209
                "code": "ZW"
1210
              }
1211
            ]
1212
          },
1213
          "valueProperty": "name",
1214
          "template": "<span>{{ item.name }}</span>",
1215
          "validateWhenHidden": false,
1216
          "key": "Country",
1217
          "type": "select",
1218
          "input": true
1219
        },
1220
        {
1221
          "label": "Home Phone",
1222
          "applyMaskOn": "change",
1223
          "tableView": true,
1224
          "validateWhenHidden": false,
1225
          "key": "HomePhone",
1226
          "type": "phoneNumber",
1227
          "input": true
1228
        },
1229
        {
1230
          "label": "Extension",
1231
          "applyMaskOn": "change",
1232
          "mask": false,
1233
          "tableView": false,
1234
          "delimiter": false,
1235
          "requireDecimal": false,
1236
          "inputFormat": "plain",
1237
          "truncateMultipleSpaces": false,
1238
          "validateWhenHidden": false,
1239
          "key": "Extension",
1240
          "type": "number",
1241
          "input": true
1242
        },
1243
        {
1244
          "label": "Notes",
1245
          "applyMaskOn": "change",
1246
          "autoExpand": false,
1247
          "tableView": true,
1248
          "validateWhenHidden": false,
1249
          "key": "Notes",
1250
          "type": "textarea",
1251
          "input": true
1252
        },
1253
        {
1254
          "label": "ReportsTo",
1255
          "optionsLabelPosition": "right",
1256
          "inline": false,
1257
          "tableView": false,
1258
          "values": [
1259
            {
1260
              "label": " Buchanan, Steven",
1261
              "value": " Buchanan, Steven",
1262
              "shortcut": ""
1263
            },
1264
            {
1265
              "label": "Callahan, Laura",
1266
              "value": "Callahan, Laura",
1267
              "shortcut": ""
1268
            },
1269
            {
1270
              "label": "Davolio, Nancy",
1271
              "value": "Davolio, Nancy",
1272
              "shortcut": ""
1273
            },
1274
            {
1275
              "label": "Dodsworth, Anne",
1276
              "value": "Dodsworth, Anne",
1277
              "shortcut": ""
1278
            },
1279
            {
1280
              "label": "Fuller, Andrew",
1281
              "value": "Fuller, Andrew",
1282
              "shortcut": ""
1283
            },
1284
            {
1285
              "label": "King, Robert",
1286
              "value": "King, Robert",
1287
              "shortcut": ""
1288
            },
1289
            {
1290
              "label": "Leverling, Janet",
1291
              "value": "Leverling, Janet",
1292
              "shortcut": ""
1293
            },
1294
            {
1295
              "label": "Peacock, Margaret",
1296
              "value": "Peacock, Margaret",
1297
              "shortcut": ""
1298
            },
1299
            {
1300
              "label": "Suyama, Michael",
1301
              "value": "Suyama, Michael",
1302
              "shortcut": ""
1303
            }
1304
          ],
1305
          "validateWhenHidden": false,
1306
          "key": "ReportsTo",
1307
          "type": "radio",
1308
          "input": true
1309
        }
1310
      ]
1311
    },
1312
    {
1313
      "label": "Save",
1314
      "showValidations": false,
1315
      "disableOnInvalid": true,
1316
      "tableView": false,
1317
      "key": "submit",
1318
      "type": "button",
1319
      "saveOnEnter": false,
1320
      "input": true
1321
    }
1322
  ]
1323
}
1324
```
1325
1326
1327
## HTML Template
1328
1329
``` html
1330
<!DOCTYPE html>
1331
<html lang="en">
1332
1333
<head>
1334
    <meta name="viewport"
1335
        content="user-scalable=no, initial-scale=1.0001, maximum-scale=1.0001, width=device-width, minimal-ui shrink-to-fit=no">
1336
    <meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1.0" />
1337
    <title>Northwind</title>
1338
1339
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
1340
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css">
1341
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css">
1342
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/awesome-notifications/3.1.0/style.min.css">
1343
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/w2ui@2.0.0/w2ui-2.0.min.css">
1344
    <script src="https://cdnjs.cloudflare.com/ajax/libs/awesome-notifications/3.1.0/modern.var.min.js"></script>
1345
    <script src="https://cdn.jsdelivr.net/npm/localstorage-slim"></script>
1346
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
1347
    <script src="https://cdn.form.io/js/formio.embed.js"></script>
1348
</head>
1349
1350
<body>
1351
    <style>
1352
        button[type="submit"] {
1353
            background-color: #007bff;
1354
            color: white;
1355
            padding: 10px 15px;
1356
            border: none;
1357
            border-radius: 4px;
1358
            cursor: pointer;
1359
            font-size: 1em;
1360
            width: 100%;
1361
        }
1362
    </style>
1363
    <div id="toolbar"></div>
1364
    <div id="formio"></div>
1365
    <script type="module">
1366
        import { w2toolbar } from "https://cdn.jsdelivr.net/npm/w2ui@2.0.0/w2ui-2.0.es6.min.js";
1367
        var $ds = {};
1368
        var email = ls.get("email");
1369
        var notifier = new AWN({ option: "top-right" });
1370
        var sid = ls.get("sid");
1371
1372
        $(function () {
1373
            if (sid) {
1374
                google.script.run
1375
                    .withSuccessHandler(onCheckSidSuccess)
1376
                    .withFailureHandler(onInvalidSid)
1377
                    .checkSid(sid);
1378
            }
1379
            else {
1380
                onInvalidSid();
1381
            }
1382
        });
1383
1384
        function onInvalidSid(err) {
1385
            if (err) {
1386
                notifier.warning(err.message);
1387
            }
1388
            else {
1389
                let url = "<?!= base ?>?url=/form/login&callback=<?!= url ?>";
1390
                notifier.modal(`<b>You need to login to access this page.</b><br><a href="${url}">👉 <b>Login</b></a>`)
1391
            }
1392
        }
1393
1394
        function onCheckSidSuccess(valid) {
1395
            new w2toolbar({
1396
                box: "#toolbar",
1397
                name: "toolbar",
1398
                items: [
1399
                    {
1400
                        type: "menu", id: "sales", icon: "w2ui-icon-info", text: "Sales",
1401
                        items: [
1402
                            { id: "customers", text: "Customers", icon: "fa fa-user" },
1403
                            { id: "orders", text: "Orders", icon: "fa fa-file-text" },
1404
                        ]
1405
                    },
1406
                    { type: "break" },
1407
                    {
1408
                        type: "menu", id: "operations", icon: "w2ui-icon-settings", text: "Operations",
1409
                        items: [
1410
                            { id: "employees", text: "Employees", icon: "fa fa-address-card" },
1411
                            { id: "products", text: "Products", icon: "fa fa-archive" },
1412
                            { id: "categories", text: "Product Categories", icon: "fa fa-sitemap" },
1413
                            { id: "suppliers", text: "Suppliers", icon: "fa fa-user" },
1414
                            { id: "shippers", text: "Shippers", icon: "fa fa-shopping-cart" }
1415
                        ]
1416
                    },
1417
                    { type: "spacer" },
1418
                    {
1419
                        type: "menu", id: "auth", text: email,
1420
                        items: [
1421
                            { text: "Logout", id: "logout", icon: "fa fa-sign-out" }
1422
                        ]
1423
                    }
1424
                ],
1425
                onClick(event) {
1426
                    switch (event.target) {
1427
                        case "sales:customers": {
1428
                            window.open("<?= base ?>?url=/form/customers", "_top");
1429
                            break;
1430
                        }
1431
                        case "sales:orders": {
1432
                            window.open("<?= base ?>?url=/form/orders", "_top");
1433
                            break;
1434
                        }
1435
                        case "operations:employees": {
1436
                            window.open("<?= base ?>?url=/form/employees", "_top");
1437
                            break;
1438
                        }
1439
                        case "operations:products": {
1440
                            window.open("<?= base ?>?url=/form/products", "_top");
1441
                            break;
1442
                        }
1443
                        case "operations:categories": {
1444
                            window.open("<?= base ?>?url=/form/categories", "_top");
1445
                            break;
1446
                        }
1447
                        case "operations:suppliers": {
1448
                            window.open("<?= base ?>?url=/form/suppliers", "_top");
1449
                            break;
1450
                        }
1451
                        case "operations:shippers": {
1452
                            window.open("<?= base ?>?url=/form/shippers", "_top");
1453
                            break;
1454
                        }
1455
                        case "auth:logout": {
1456
                            ls.remove("sid");
1457
                            ls.remove("email");
1458
                            window.open("<?= base ?>?url=/form/login&callback=<?!= url ?>", "_top");
1459
                            break;
1460
                        }
1461
                    }
1462
                }
1463
            });
1464
1465
            if (valid) {
1466
                google.script.run.withSuccessHandler(showForms)
1467
                    .loadDatasources("<?!= datasource ?>");
1468
            } else {
1469
                onInvalidSid();
1470
            }
1471
        }
1472
1473
        function showForms(ds) {
1474
            $ds = ds;
1475
            let rec = <?!= (data) ?>;
1476
            Formio.createForm(document.getElementById("formio"), <?!= template ?>)
1477
                .then(function (form) {
1478
                    // Prevent the submission from going to the form.io server.
1479
                    form.noAlerts = true;
1480
                    form.nosubmit = true;
1481
                    form.submission = rec.Document ? { data: JSON.parse(rec.Document) } : {};
1482
1483
                    // Triggered when they click the submit button.
1484
                    form.on("submit", function (submission) {
1485
                        google.script.run
1486
                            .withFailureHandler((err) => {
1487
                                notifier.warning("Successfully saved.");
1488
                                form.emit("submitError");
1489
                            })
1490
                            .withSuccessHandler((id) => {
1491
                                if (!id) {
1492
                                    form.emit("submitError");
1493
                                    notifier.warning("An error occurred while saving the entry.");
1494
                                }
1495
                                else {
1496
                                    form.emit("submitDone");
1497
                                    <? if (!id) { ?>
1498
                                    form.submission = {};
1499
                                    form.refresh();
1500
                                    <? } ?>
1501
                                    notifier.success("Successfully saved.");
1502
                                }
1503
                            })
1504
                            <? if (id) { ?>
1505
                        .update("<?!= id ?>", "<?!= form.Id ?>", { Document: JSON.stringify(submission.data) }, null, sid)
1506
                                <? } else { ?>
1507
                        .create("<?!= form.Id ?>", { Document: JSON.stringify(submission.data) }, sid);
1508
                        <? } ?>
1509
                    });
1510
                });
1511
        }
1512
    </script>
1513
</body>
1514
1515
</html>
1516
```
1517
1518
## Giải thích Code
1519
1520
Form List Employees sử dụng cácthư viện sau:
1521
- [jQuery](https://jquery.com/) để khởi tạo grid sau khi page load xong.
1522
- [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.
1523
- [Notyf](https://carlosroso.com/notyf/) hiển thị thông báo.
1524
- [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...
1525
- 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. 
1526
- Trong page này gọi đến
1527
  - 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
1528
  - Hàm backend **loadDatasources** để tải các dữ liệu tham chiếu phía client, ví dụ danh sách Products
1529 2 Lê Sĩ Quý
  - Hàm backend **create** để lưu form submission dưới dạng document trong database NoSQL
1530
  - 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 của document.
1531 1 Lê Sĩ Quý
1532
## Demo
1533 3 Lê Sĩ Quý
- Link: https://script.google.com/macros/s/AKfycbwIjB-hULVZdfCtsXFPg4Af_8WoKx2AFf85KMVwnsO_WkeAXW3zarT6vZNFVfwccz1_sA/exec?url=/form/crud-employee
1534 1 Lê Sĩ Quý
- Account: user@northwind.com
1535
- Password: user