Google 表单提交按钮的 onClick 事件
onClick event for Google Forms Submit button
这快把我逼疯了,我有一个简单的 Google 表格可以接受订户代码和他们的时隙时间。我的目的是通过 Google 表格获取数据并将其保存到 Google 工作表 而不会在插槽时间 .
中发生任何冲突
为了向您展示一个示例,我附上了我的表格和 sheet 的图片。完成第一个条目后,如果要将另一个时隙分配给同一订阅者,我们需要确保时隙时序不会与分配给同一订阅者的 google sheet 中保存的时序冲突订户。如果您看到第二个条目,它只是接受它,为此我们需要一个不可用的验证检查。我的问题是,是否有可能在提交按钮上进行 onClick 验证?我一直在 google 上疯狂地搜索它,但没有找到解决方案。如果无法以 Google 形式执行此操作,我有哪些替代方案或是否有任何可用的解决方法?
热切等待对我的查询的回复。谢谢。
您可以在当前设置上尝试的另一个想法是,您可以使用 onFormSubmit
触发器。提交响应后,会将其与添加到 sheet 的先前行进行比较,以检查是否与您的数据有任何冲突。
确认有后,去掉最后一条回复即可。如果没有冲突,那就让它结束吧。
Sheet 脚本:
function checkConflict(e) {
var sheet = e.range.getSheet();
var lastRow = sheet.getLastRow();
// exclude the last submitted response
var timeSlots = sheet.getRange(2, 3, lastRow - 2, 2).getValues();
var lastResponse = e.values;
var lastStart = new Date(lastResponse[2]).getTime();
var lastEnd = new Date(lastResponse[3]).getTime();
// convert timeslots to comparable data type
timeSlots = timeSlots.map(timeSlot => [timeSlot[0].getTime(), timeSlot[1].getTime()]);
// get conflicts
var conflict = timeSlots.filter(timeSlot => (timeSlot[0] <= lastStart && timeSlot[1] >= lastStart) ||
(timeSlot[0] <= lastEnd && timeSlot[1] >= lastEnd));
// remove lastRow if conflict is 1
if(conflict.length) {
sheet.deleteRow(lastRow);
MailApp.sendEmail(lastResponse[4],
"Time Slot conflict",
"Your recent response was removed due to a conflict. Your submitted time slot is the following:\n" +
"From: " + new Date(lastStart) + "\n" +
"To: " + new Date(lastEnd));
}
else {
MailApp.sendEmail(lastResponse[4],
"Time Slot confirmed",
"Your time slot is now confirmed. Confirmed time slot is the following:\n " +
"From: " + new Date(lastStart) + "\n" +
"To: " + new Date(lastEnd));
}
}
示例数据:
触发器:
电子邮件确认:
电子邮件冲突:
输出:
注:
- 此方法不会在提交前检查您的输入。它只是删除了之后的最后一个响应 IF 与之前的时隙时间冲突。
- 此外,发送回复的人不会知道他的广告位是否已确认,除非您在表格中要求他的电子邮件并在检查后发送确认(他提交的回复是否由于以下原因被删除)冲突,或者因为没有冲突而被批准)
- 如果您有 9:00 - 10:00 的时间段,它不会接受另一个包含 9:00 的响应,因为 (>=, <=) 包含在内。您可以选择开始时间为 1/31 分钟(例如
9:01-10:00
、8:31-9:30
)或结束时间为 59/29 分钟(例如 9:00-9:59
、8:30-9:29
).
- 如果这很麻烦,那么您需要调整检查冲突的条件。你应该能想出来。
正如@Cooper 指出的那样,您最好创建自己的网络应用程序。
经过几个小时的工作,我制作了一个 web app that will work for you using Google Apps Script. Here 电子表格和脚本文件。
服务器端代码:
var ss = SpreadsheetApp.getActiveSheet()
function doGet() {
return HtmlService.createTemplateFromFile('form').evaluate()
}
function submitData (data) {
ss.appendRow([new Date(),data.ssCode, new Date(data.startDateTime), new Date(data.endDateTime)])
}
function isAvailible (start, end) {
var data = ss.getDataRange().getValues()
var isAvailible = true;
var message = '';
data.forEach(row => {
if(start > row[2].valueOf() && start < row[3].valueOf() || end > row[2].valueOf() && end < row[3].valueOf()) {
isAvailible = false;
message = new Date(row[2].valueOf()) +'<br> to ' + new Date(row[3].valueOf()) + '<br> isn\'t availible.'
}
})
var response = {status: isAvailible, message: message}
return response;
}
客户端代码:
M.FormSelect.init(document.querySelectorAll('select'));
var dps = document.querySelectorAll('.datepicker');
var dpsInstances = M.Datepicker.init(dps, {
showClearBtn: true,
autoClose: true
});
dpsInstances[0].options.onSelect = function(day) {
dpsInstances[1].setDate(day);
endDate.value = dpsInstances[1].toString()
M.updateTextFields();
}
var tps = document.querySelectorAll('.timepicker');
var tpsInstances = M.Timepicker.init(tps, {
twelveHour: false,
showClearBtn: true,
autoClose: true
});
function formSubmit(data) {
var startDate = new Date(data.startDate.value);
var startTime = data.startTime.value.split(':');
startDate.setHours(startTime[0]);
startDate.setMinutes(startTime[1]);
var endDate = new Date(data.endDate.value);
var endTime = data.endTime.value.split(':')
endDate.setHours(endTime[0]);
endDate.setMinutes(endTime[1]);
if (startDate.valueOf() >= endDate.valueOf()) {
M.toast({html: 'End date should be greater then start date.'})
return;
}
var dataToSubmit = {
ssCode: data.ssCode.value,
startDateTime: startDate.valueOf(),
endDateTime: endDate.valueOf()
}
google.script.run.withSuccessHandler(function(response) {
if (response.status) {
google.script.run.withSuccessHandler(function() {
myForm.reset()
M.toast({
html: "Successful"
})
}).submitData(dataToSubmit)
} else {
M.toast({
html: response.message
})
}
}).isAvailible(dataToSubmit.startDateTime, dataToSubmit.endDateTime)
}
body {
background: rgb(244, 235, 234)
}
.outer-field {
border-radius: 15px;
background: white;
height: 150px;
margin: 10px;
padding: 20px;
}
.title {
padding-left: 2%;
font-weight: bold;
}
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div class="row">
<div class="col s10 offset-s1 l4 offset-l4">
<div class="outer-field" style="height: 100px">
<h4>Slot Timings</h4>
</div>
<form id="myForm" onsubmit="event.preventDefault(); formSubmit(this) ">
<div class="outer-field">
<div class="title">Subscriber Code</div>
<div class="input-field col s6 l6">
<select form="myForm" name="ssCode" required>
<option value="001">001</option>
<option value="002">002</option>
<option value="003">003</option>
</select>
</div>
</div>
<div class="outer-field">
<div class="title">From</div>
<div class="col s6 l6">
<div class="input-field">
<input type="text" id="startDate" name="startDate" class="datepicker validate" form="myForm" required>
<label for="startDate">Date</label>
</div>
</div>
<div class="col s6 l6">
<div class="input-field">
<input type="text" id="startTime" name="startTime" class="timepicker validate" form="myForm" required>
<label for="startTime">Time</label>
</div>
</div>
</div>
<div class="outer-field">
<div class="title">To</div>
<div class="col s6 l6">
<div class="input-field">
<input type="text" id="endDate" name="endDate" class="datepicker" form="myForm" required>
<label for="endDate">Date</label>
</div>
</div>
<div class="col s6 l6">
<div class="input-field">
<input type="text" id="endTime" name="endTime" class="timepicker" form="myForm" required>
<label for="endTime">Time</label>
</div>
</div>
</div>
<button class="btn waves-effect waves-light" type="submit" name="action" style="margin-left: 3%" >Submit
<i class="material-icons right">send</i>
</button>
</form>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
</html>
这快把我逼疯了,我有一个简单的 Google 表格可以接受订户代码和他们的时隙时间。我的目的是通过 Google 表格获取数据并将其保存到 Google 工作表 而不会在插槽时间 .
中发生任何冲突为了向您展示一个示例,我附上了我的表格和 sheet 的图片。完成第一个条目后,如果要将另一个时隙分配给同一订阅者,我们需要确保时隙时序不会与分配给同一订阅者的 google sheet 中保存的时序冲突订户。如果您看到第二个条目,它只是接受它,为此我们需要一个不可用的验证检查。我的问题是,是否有可能在提交按钮上进行 onClick 验证?我一直在 google 上疯狂地搜索它,但没有找到解决方案。如果无法以 Google 形式执行此操作,我有哪些替代方案或是否有任何可用的解决方法?
热切等待对我的查询的回复。谢谢。
您可以在当前设置上尝试的另一个想法是,您可以使用 onFormSubmit
触发器。提交响应后,会将其与添加到 sheet 的先前行进行比较,以检查是否与您的数据有任何冲突。
确认有后,去掉最后一条回复即可。如果没有冲突,那就让它结束吧。
Sheet 脚本:
function checkConflict(e) {
var sheet = e.range.getSheet();
var lastRow = sheet.getLastRow();
// exclude the last submitted response
var timeSlots = sheet.getRange(2, 3, lastRow - 2, 2).getValues();
var lastResponse = e.values;
var lastStart = new Date(lastResponse[2]).getTime();
var lastEnd = new Date(lastResponse[3]).getTime();
// convert timeslots to comparable data type
timeSlots = timeSlots.map(timeSlot => [timeSlot[0].getTime(), timeSlot[1].getTime()]);
// get conflicts
var conflict = timeSlots.filter(timeSlot => (timeSlot[0] <= lastStart && timeSlot[1] >= lastStart) ||
(timeSlot[0] <= lastEnd && timeSlot[1] >= lastEnd));
// remove lastRow if conflict is 1
if(conflict.length) {
sheet.deleteRow(lastRow);
MailApp.sendEmail(lastResponse[4],
"Time Slot conflict",
"Your recent response was removed due to a conflict. Your submitted time slot is the following:\n" +
"From: " + new Date(lastStart) + "\n" +
"To: " + new Date(lastEnd));
}
else {
MailApp.sendEmail(lastResponse[4],
"Time Slot confirmed",
"Your time slot is now confirmed. Confirmed time slot is the following:\n " +
"From: " + new Date(lastStart) + "\n" +
"To: " + new Date(lastEnd));
}
}
示例数据:
触发器:
电子邮件确认:
电子邮件冲突:
输出:
注:
- 此方法不会在提交前检查您的输入。它只是删除了之后的最后一个响应 IF 与之前的时隙时间冲突。
- 此外,发送回复的人不会知道他的广告位是否已确认,除非您在表格中要求他的电子邮件并在检查后发送确认(他提交的回复是否由于以下原因被删除)冲突,或者因为没有冲突而被批准)
- 如果您有 9:00 - 10:00 的时间段,它不会接受另一个包含 9:00 的响应,因为 (>=, <=) 包含在内。您可以选择开始时间为 1/31 分钟(例如
9:01-10:00
、8:31-9:30
)或结束时间为 59/29 分钟(例如9:00-9:59
、8:30-9:29
). - 如果这很麻烦,那么您需要调整检查冲突的条件。你应该能想出来。
正如@Cooper 指出的那样,您最好创建自己的网络应用程序。
经过几个小时的工作,我制作了一个 web app that will work for you using Google Apps Script. Here 电子表格和脚本文件。
服务器端代码:
var ss = SpreadsheetApp.getActiveSheet()
function doGet() {
return HtmlService.createTemplateFromFile('form').evaluate()
}
function submitData (data) {
ss.appendRow([new Date(),data.ssCode, new Date(data.startDateTime), new Date(data.endDateTime)])
}
function isAvailible (start, end) {
var data = ss.getDataRange().getValues()
var isAvailible = true;
var message = '';
data.forEach(row => {
if(start > row[2].valueOf() && start < row[3].valueOf() || end > row[2].valueOf() && end < row[3].valueOf()) {
isAvailible = false;
message = new Date(row[2].valueOf()) +'<br> to ' + new Date(row[3].valueOf()) + '<br> isn\'t availible.'
}
})
var response = {status: isAvailible, message: message}
return response;
}
客户端代码:
M.FormSelect.init(document.querySelectorAll('select'));
var dps = document.querySelectorAll('.datepicker');
var dpsInstances = M.Datepicker.init(dps, {
showClearBtn: true,
autoClose: true
});
dpsInstances[0].options.onSelect = function(day) {
dpsInstances[1].setDate(day);
endDate.value = dpsInstances[1].toString()
M.updateTextFields();
}
var tps = document.querySelectorAll('.timepicker');
var tpsInstances = M.Timepicker.init(tps, {
twelveHour: false,
showClearBtn: true,
autoClose: true
});
function formSubmit(data) {
var startDate = new Date(data.startDate.value);
var startTime = data.startTime.value.split(':');
startDate.setHours(startTime[0]);
startDate.setMinutes(startTime[1]);
var endDate = new Date(data.endDate.value);
var endTime = data.endTime.value.split(':')
endDate.setHours(endTime[0]);
endDate.setMinutes(endTime[1]);
if (startDate.valueOf() >= endDate.valueOf()) {
M.toast({html: 'End date should be greater then start date.'})
return;
}
var dataToSubmit = {
ssCode: data.ssCode.value,
startDateTime: startDate.valueOf(),
endDateTime: endDate.valueOf()
}
google.script.run.withSuccessHandler(function(response) {
if (response.status) {
google.script.run.withSuccessHandler(function() {
myForm.reset()
M.toast({
html: "Successful"
})
}).submitData(dataToSubmit)
} else {
M.toast({
html: response.message
})
}
}).isAvailible(dataToSubmit.startDateTime, dataToSubmit.endDateTime)
}
body {
background: rgb(244, 235, 234)
}
.outer-field {
border-radius: 15px;
background: white;
height: 150px;
margin: 10px;
padding: 20px;
}
.title {
padding-left: 2%;
font-weight: bold;
}
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div class="row">
<div class="col s10 offset-s1 l4 offset-l4">
<div class="outer-field" style="height: 100px">
<h4>Slot Timings</h4>
</div>
<form id="myForm" onsubmit="event.preventDefault(); formSubmit(this) ">
<div class="outer-field">
<div class="title">Subscriber Code</div>
<div class="input-field col s6 l6">
<select form="myForm" name="ssCode" required>
<option value="001">001</option>
<option value="002">002</option>
<option value="003">003</option>
</select>
</div>
</div>
<div class="outer-field">
<div class="title">From</div>
<div class="col s6 l6">
<div class="input-field">
<input type="text" id="startDate" name="startDate" class="datepicker validate" form="myForm" required>
<label for="startDate">Date</label>
</div>
</div>
<div class="col s6 l6">
<div class="input-field">
<input type="text" id="startTime" name="startTime" class="timepicker validate" form="myForm" required>
<label for="startTime">Time</label>
</div>
</div>
</div>
<div class="outer-field">
<div class="title">To</div>
<div class="col s6 l6">
<div class="input-field">
<input type="text" id="endDate" name="endDate" class="datepicker" form="myForm" required>
<label for="endDate">Date</label>
</div>
</div>
<div class="col s6 l6">
<div class="input-field">
<input type="text" id="endTime" name="endTime" class="timepicker" form="myForm" required>
<label for="endTime">Time</label>
</div>
</div>
</div>
<button class="btn waves-effect waves-light" type="submit" name="action" style="margin-left: 3%" >Submit
<i class="material-icons right">send</i>
</button>
</form>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
</html>