Senin, 12 Januari 2026

Data Entry HTML Form

 






https://codestudio80.blogspot.com/2026/01/data-entry-using-html-form-with-file.html

PROMPT

Buatkan aplikasi Single Page Application (SPA) berbasis Google Apps Script
dengan backend menggunakan Code.gs dan frontend index.html.

Spesifikasi Umum:
- Platform: Google Apps Script Web App
- Arsitektur: SPA (tanpa reload halaman)
- Frontend dipanggil melalui function doGet(e)
- Komunikasi frontend-backend menggunakan google.script.run
- UI sederhana dan responsif (gunakan Bulma CSS)
- Data disimpan di Google Spreadsheet
- Upload file disimpan ke Google Drive

Backend (Code.gs):
1. Gunakan function doGet(e) untuk memanggil file index.html
2. Tambahkan konfigurasi:
   - SPREADSHEET_ID
   - FOLDER_ID
   - SHEET_NAME
3. Buat function initializeSheet():
   - Mengecek apakah sheet sudah ada
   - Jika belum, buat sheet
   - Jika sheet kosong, buat header kolom:
     ID
     Timestamp
     Client Name
     Email
     Password
     DOB
     Gender
     Notes
     Agree To Terms
     File URL
   - Freeze baris header
4. Buat function submitForm(data):
   - Menerima data dari frontend
   - Generate UUID sebagai ID
   - Timestamp otomatis
   - Upload file (Base64) ke Google Drive
   - Simpan URL file ke Spreadsheet
   - Kembalikan response JSON {status, message}
5. Buat function uploadFile_(file):
   - Decode Base64
   - Simpan file ke Drive folder
   - Return URL file

Frontend (index.html):
1. SPA berbasis HTML + JavaScript
2. Gunakan Bulma CSS
3. Buat form dengan field:
   - Client Name (required)
   - Email (required, type email)
   - Password
   - Date of Birth
   - Gender (radio)
   - Notes (textarea)
   - Agree to Terms (checkbox)
   - File upload
4. Tidak menggunakan fetch API
5. Submit data menggunakan google.script.run.submitForm()
6. Tampilkan notifikasi:
   - Loading
   - Success
   - Error
7. Setelah submit berhasil:
   - Form reset
   - Tidak reload halaman

Tambahan:
- Kode harus rapi, modular, dan mudah dikembangkan
- Siap dikembangkan menjadi CRUD (Read, Update, Delete)
- Sertakan komentar penjelasan pada setiap bagian kode

Output yang diharapkan:
- File Code.gs lengkap
- File index.html lengkap
- Siap langsung dideploy sebagai Web App

Code.gs

/********** KONFIGURASI **********/
const SPREADSHEET_ID = '1tI5_Q6Yu06OG_sJgFkodkjB37J5tNVN6hKcacqObtLE';
const FOLDER_ID = '1IHFhDlDi_hIuteGZ7Kx07VgNfKK4Hly4';
const SHEET_NAME = 'Data';

/********** ENTRY POINT SPA **********/
function doGet(e) {
initializeSheet();

return HtmlService.createHtmlOutputFromFile('index')
.setTitle('SISKO DB | Smart School System')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
.addMetaTag('viewport', 'width=device-width, initial-scale=1.0')
.setFaviconUrl('https://cdn-icons-png.flaticon.com/512/201/201614.png');
}

/********** INITIALIZE SHEET **********/
function initializeSheet() {
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
let sheet = ss.getSheetByName(SHEET_NAME);

if (!sheet) {
sheet = ss.insertSheet(SHEET_NAME);
}

if (sheet.getLastRow() === 0) {
sheet.appendRow([
'ID',
'Timestamp',
'Client Name',
'Email',
'Password',
'DOB',
'Gender',
'Notes',
'Agree To Terms',
'File URL'
]);
sheet.setFrozenRows(1);
}
}

/********** SUBMIT FORM (SPA) **********/
function submitForm(data) {
try {
initializeSheet();

const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheet = ss.getSheetByName(SHEET_NAME);

let fileUrl = '';
if (data.fileData) {
fileUrl = uploadFile_(data.fileData);
}

sheet.appendRow([
Utilities.getUuid(),
new Date(),
data['Client Name'],
data['Email'],
data['Password'],
data['DOB'],
data['Gender'],
data['Notes'],
data['Agree To Terms'] || '',
fileUrl
]);

return {
status: 'success',
message: 'Data berhasil disimpan'
};
} catch (err) {
return {
status: 'error',
message: err.message
};
}
}

/********** UPLOAD FILE **********/
function uploadFile_(file) {
const folder = DriveApp.getFolderById(FOLDER_ID);
const blob = Utilities.newBlob(
Utilities.base64Decode(file.data),
file.mimeType,
file.fileName
);
const createdFile = folder.createFile(blob);
return createdFile.getUrl();
}

Index.html

<!DOCTYPE html>
<html>
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"
>

<title>SISKO DB</title>
</head>

<body>
<section class="hero is-primary">
<div class="hero-body">
<h1 class="title">Data Entry Form (SPA)</h1>
<p class="subtitle">Google Apps Script + Spreadsheet</p>
</div>
</section>

<section class="section">
<form id="form" class="box">

<input class="input mb-3" name="Client Name" placeholder="Client Name" required>
<input class="input mb-3" name="Email" type="email" placeholder="Email" required>
<input class="input mb-3" name="Password" type="password" placeholder="Password" required>
<input class="input mb-3" name="DOB" type="date">

<div class="mb-3">
<label class="radio">
<input type="radio" name="Gender" value="Male"> Male
</label>
<label class="radio ml-3">
<input type="radio" name="Gender" value="Female"> Female
</label>
</div>

<textarea class="textarea mb-3" name="Notes" placeholder="Notes"></textarea>

<label class="checkbox mb-3">
<input type="checkbox" name="Agree To Terms" value="Yes"> Agree to terms
</label>

<div class="file mb-4">
<label class="file-label">
<input class="file-input" type="file" id="fileInput">
<span class="file-cta">
<span class="file-label">Choose file</span>
</span>
</label>
</div>

<button class="button is-primary is-fullwidth" type="submit">
Submit
</button>
</form>

<div id="message" class="notification is-hidden mt-4"></div>
</section>

<script>
const form = document.getElementById('form');
const fileInput = document.getElementById('fileInput');
const message = document.getElementById('message');

function readFile(file) {
return new Promise(resolve => {
const fr = new FileReader();
fr.onload = e => {
const data = e.target.result.split(',');
resolve({
fileName: file.name,
mimeType: data[0].match(/:(.*?);/)[1],
data: data[1]
});
};
fr.readAsDataURL(file);
});
}

form.addEventListener('submit', async e => {
e.preventDefault();

message.className = 'notification is-info';
message.textContent = 'Submitting...';
message.classList.remove('is-hidden');

const fd = new FormData(form);
const data = Object.fromEntries(fd.entries());

if (fileInput.files.length > 0) {
data.fileData = await readFile(fileInput.files[0]);
}

google.script.run
.withSuccessHandler(res => {
message.className =
res.status === 'success'
? 'notification is-success'
: 'notification is-danger';
message.textContent = res.message;
form.reset();
})
.withFailureHandler(err => {
message.className = 'notification is-danger';
message.textContent = err.message;
})
.submitForm(data);
});
</script>
</body>
</html>


Tidak ada komentar:

Posting Komentar

Data Entry HTML Form

  https://script.google.com/macros/s/AKfycbzeeqBQE-i7x8kKFswdyGVIgyydxTU0Y617eMjD6ve0Xm8c6-UqqHN3sPSi8zFlfnDGew/exec https://sites.google.co...