Найдено на просторах интернета. Ознакомится с первоисточником можно тут.
Для работы потребуется два скрипта.
Первый скрипты встравиваем в google таблицы:
/******************************************************************************
* This tutorial is based on the work of Martin Hawksey twitter.com/mhawksey *
* But has been simplified and cleaned up to make it more beginner friendly *
* All credit still goes to Martin and any issues/complaints/questions to me. *
******************************************************************************/
// if you want to store your email server-side (hidden), uncomment the next line
var TO_ADDRESS = "you@email.ru";
// spit out all the keys/values from the form in HTML for email
// uses an array of keys if provided or the object to determine field order
function formatMailBody(obj, order) {
var result = "";
if (!order) {
order = Object.keys(obj);
}
// loop over all keys in the ordered form data
for (var idx in order) {
var key = order[idx];
result += "<h4 style='text-transform: capitalize; margin-bottom: 0'>" + key + "</h4><div>" + sanitizeInput(obj[key]) + "</div>";
// for every key, concatenate an `<h4 />`/`<div />` pairing of the key name and its value,
// and append it to the `result` string created at the start.
}
return result; // once the looping is done, `result` will be one long string to put in the email body
}
// sanitize content from the user - trust no one
// ref: https://developers.google.com/apps-script/reference/html/html-output#appendUntrusted(String)
function sanitizeInput(rawInput) {
var placeholder = HtmlService.createHtmlOutput(" ");
placeholder.appendUntrusted(rawInput);
return placeholder.getContent();
}
function doPost(e) {
try {
Logger.log(e); // the Google Script version of console.log see: Class Logger
record_data(e);
// shorter name for form data
var mailData = e.parameters;
// names and order of form elements (if set)
var orderParameter = e.parameters.formDataNameOrder;
var dataOrder;
if (orderParameter) {
dataOrder = JSON.parse(orderParameter);
}
// determine recepient of the email
// if you have your email uncommented above, it uses that `TO_ADDRESS`
// otherwise, it defaults to the email provided by the form's data attribute
var sendEmailTo = (typeof TO_ADDRESS !== "undefined") ? TO_ADDRESS : mailData.formGoogleSendEmail;
// send email if to address is set
if (sendEmailTo) {
MailApp.sendEmail({
to: String(sendEmailTo),
subject: "Contact form submitted",
// replyTo: String(mailData.email), // This is optional and reliant on your form actually collecting a field named `email`
htmlBody: formatMailBody(mailData, dataOrder)
});
}
return ContentService // return json success results
.createTextOutput(
JSON.stringify({"result":"success",
"data": JSON.stringify(e.parameters) }))
.setMimeType(ContentService.MimeType.JSON);
} catch(error) { // if error return this
Logger.log(error);
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": error}))
.setMimeType(ContentService.MimeType.JSON);
}
}
/**
* record_data inserts the data received from the html form submission
* e is the data received from the POST
*/
function record_data(e) {
var lock = LockService.getDocumentLock();
lock.waitLock(30000); // hold off up to 30 sec to avoid concurrent writing
try {
Logger.log(JSON.stringify(e)); // log the POST data in case we need to debug it
// select the 'responses' sheet by default
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = e.parameters.formGoogleSheetName || "form_site";
var sheet = doc.getSheetByName(sheetName);
var oldHeader = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var newHeader = oldHeader.slice();
var fieldsFromForm = getDataColumns(e.parameters);
var row = [new Date()]; // first element in the row should always be a timestamp
// loop through the header columns
for (var i = 1; i < oldHeader.length; i++) { // start at 1 to avoid Timestamp column
var field = oldHeader[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
// mark as stored by removing from form fields
var formIndex = fieldsFromForm.indexOf(field);
if (formIndex > -1) {
fieldsFromForm.splice(formIndex, 1);
}
}
// set any new fields in our form
for (var i = 0; i < fieldsFromForm.length; i++) {
var field = fieldsFromForm[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
newHeader.push(field);
}
// more efficient to set values as [][] array than individually
var nextRow = sheet.getLastRow() + 1; // get next row
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// update header row with any new data
if (newHeader.length > oldHeader.length) {
sheet.getRange(1, 1, 1, newHeader.length).setValues([newHeader]);
}
}
catch(error) {
Logger.log(error);
}
finally {
lock.releaseLock();
return;
}
}
function getDataColumns(data) {
return Object.keys(data).filter(function(column) {
return !(column === 'formDataNameOrder' || column === 'formGoogleSheetName' || column === 'formGoogleSendEmail' || column === 'honeypot');
});
}
function getFieldFromData(field, data) {
var values = data[field] || '';
var output = values.join ? values.join(', ') : values;
return output;
}
В 8 строке указываем почтовый ящик куда будут приходит уведомления:
var TO_ADDRESS = "
you@email.ru
"
В 95 строке задаем в какой лист таблицы будем писать данные:
var sheetName = e.parameters.formGoogleSheetName || "
form_site
";
Далее жмем на вкладку "Опубликовать" и выбираем "Развернуть как веб приложение".
По окончанию развертывания вам должно выдать модальное окно с url адресом приложения. Копируем ссылку.
На следующем этапе разворачиваем фронт, в качестве примера сделаем простую html страницу с формой, куда подключим наш второй скрипт.
index.html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Тестовая форма</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</head>
<body>
<form class="g-form" id="g-form-1" method="POST" action="" autocomplete="off">
<h2 class="g-form__title g-form__title_main">Тестовая форма</h2>
<h2 class="g-form__title g-form__title_respond"></h2>
<div class="g-form__preloader"></div>
<div class="g-form__inputs">
<fieldset class="g-form__input-wrapper">
<input class="g-form__input g-form__input_name" id="name" type="number" name="Столбец 1" placeholder="Столбец 1" required>
</fieldset>
<fieldset class="g-form__input-wrapper">
<input class="g-form__input g-form__input_tel" id="tel" name="Столбец 2" placeholder="Столбец 2">
</fieldset>
<fieldset class="g-form__input-wrapper">
<input id="email" name="Столбец 3" type="number" value=""
required placeholder="Столбец 3"/>
</fieldset>
<fieldset class="g-form__input-wrapper">
<input id="arbitrary-field" name="Столбец 4" type="date" placeholder="Столбец 4">
</fieldset>
<fieldset class="g-form__input-wrapper g-form__input-wrapper_hidden">
<label for="honeypot">Помогает бороться со спамом. Должно быть пустым!</label>
<input id="honeypot" type="text" name="honeypot" value="">
</fieldset>
<div class="g-form__button-wrapper">
<button class="g-form__button">Внести запись</button>
</div>
</div>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="./g-form/g-form.js"></script>
</body>
</html>
Обязательно подключаем jquery и g-form.js который создадим следующим:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="./g-form/g-form.js"></script>
script.js - Скрипт, отправляющий данные формы в Google Sheets
$(function() {
$(".g-form").submit(function (event) {
event.preventDefault();
// Ссылка, которую получили на этапе публикации приложения
let appLink = "url полученный при развертывании";
// Сообщение при успешной отправке данных
let successRespond = 'Сообщение успешно отправлено. Посмотрите результат <a target="_blank" href="https://docs.google.com/spreadsheets/d/1XcTivCQL4EZJf1x2kB4UwGj5bAi0sfpx1PwtaKgOWHo/edit?usp=sharing">тут</a>';
// Сообщение при ошибке в отправке данных
let errorRespond = 'Не удалось отправить сообщение. Cвяжитесь с администратором сайта по адресу <a href="mailto:smart-landing@ya.ru">smart-landing@ya.ru</a>';
// Id текущей формы
let form = $('#' + $(this).attr('id'))[0];
// h2 с ответом формы
let formRespond = $(this).find('.g-form__title_respond');
// h2 с заголовком формы
let formTitle = $(this).find('.g-form__title_main');
// Блок прелоадера
let preloader = $(this).find('.g-form__preloader');
// Кнопка отправки формы
let submitButton = $(this).find('.g-form__button');
// FormData
let fd = new FormData(form);
$.ajax({
url: appLink,
type: "POST",
data: fd,
processData: false,
contentType: false,
beforeSend: function(){
if(fd.get('honeypot').length) {
return false;
} else {
fd.delete('honeypot');
}
// Показываем прелоадер
preloader.css('opacity', '1');
// Делаем неактивной кнопку отправки
submitButton.prop('disabled', true);
// валидация других полей.
},
}).done(function(res, textStatus, jqXHR) {
if(jqXHR.readyState === 4 && jqXHR.status === 200) {
// Прячем заголовок формы
formTitle.css({
'display': 'none'
});
// Прячем прелоадер
preloader.css('opacity', '0');
// Выводим ответ формы.
formRespond.html(successRespond).css('color', '#37b599');
// Возвращаем активность кнопке отправки
submitButton.prop('disabled', false);
// Очищаем поля формы
form.reset();
} else {
formTitle.css({
'display': 'none'
});
formRespond.html(errorRespond).css('color', '#c64b4b');
preloader.css('opacity', '0');
setTimeout( () => {
formRespond.css({
'display': 'none'
});
formTitle.css({
'display': 'block'
});
submitButton.prop('disabled', false);
}, 5000);
console.log('Гугл не ответил статусом 200');
}
}).fail(function(res, textStatus, jqXHR) {
formTitle.css({
'display': 'none'
});
preloader.css('opacity', '0');
formRespond.html('Не удалось отправить сообщение. Cвяжитесь с администратором сайта другим способом').css('color', '#c64b4b');
setTimeout( () => {
formRespond.css({
'display': 'none'
});
formTitle.css({
'display': 'block'
});
submitButton.prop('disabled', false);
}, 5000);
console.log('Не удалось выполнить запрос по указанному в скрипте пути');
});
});
}(jQuery));
В строке let appLink = "
url полученный при развертывании
"; - вставляем полученный нами ранее при развертывании приложения URL адрес нашей таблицы.
В строке let successRespond указываем адрес самой таблицы, если необходимо после оформления проверить внеслись данные
:
let successRespond = 'Сообщение успешно отправлено. Посмотрите результат <a target="_blank" href="url адрес самой страницы">тут</a>';
let errorRespond - указываем email для связи в случае возникновения ошибки.
let errorRespond = 'Не удалось отправить сообщение. Cвяжитесь с администратором сайта по адресу <a href="mailto:smart-landing@ya.ru">you@email.ru</a>';
Обязательное условия для корректной работы формы это соотношения полей и названий столбцов таблицы:
