简体   繁体   English

Google 表单提交按钮的 onClick 事件

[英]onClick event for Google Forms Submit button

This is driving me crazy, I have a simple Google Form that accepts subscriber code and their slot timings.这让我发疯了,我有一个简单的谷歌表单,它接受订阅者代码和他们的时间安排。 My purpose is to get data via Google Forms and save it to Google Sheets without having any clashes in the slots timings .我的目的是通过 Google Forms 获取数据并将其保存到 Google Sheets 中,而不会在插槽时间上发生任何冲突

To show you an example, I am attaching an image of my form and sheet.为了向您展示一个示例,我附上了我的表单和工作表的图像。 After the first entry was done, if another slot is to be given to same subscriber, we need to ensure that the slot timings do not clash with the saved timings in google sheet that is assigned to the same subscriber.第一次输入完成后,如果要为同一订阅者分配另一个时隙,我们需要确保时隙时间不会与分配给同一订阅者的谷歌表中保存的时间冲突。 If you see the second entry, it just accepts it and for this we need a validation check which is not available.如果你看到第二个条目,它只是接受它,为此我们需要一个不可用的验证检查。 My question is, is it even possible to have an onClick validation on the submit button?我的问题是,是否可以在提交按钮上进行 onClick 验证? I have been searching for it on google like crazy but haven't got a solution.我一直在谷歌上疯狂地搜索它,但没有找到解决方案。 If this is not possible to do it in Google forms, what are my alternatives or is there any workaround available?如果在 Google 表单中无法做到这一点,我的替代方法是什么,或者是否有任何可用的解决方法?

Eagerly awaiting responses for my query.急切地等待对我的查询的答复。 Thank you.谢谢你。

在此处输入图片说明

Another idea you can try on your current setup is that you could use an onFormSubmit trigger.您可以在当前设置中尝试的另一个想法是您可以使用onFormSubmit触发器。 And once the response is submitted, it is compared to the previous rows that were added to the sheet to check if there have been any conflict with your data.提交响应后,会将其与添加到工作表中的前几行进行比较,以检查是否与您的数据有任何冲突。

Upon confirming there is, just remove the last response.确认存在后,只需删除最后一个响应。 If no conflict, then let it be and end the script there.如果没有冲突,那就让它存在并在那里结束脚本。

Sheet Script:工作表脚本:

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));
  }
}

Sample Data:样本数据:

样本

Trigger:扳机:

扳机

Emails confirm:电子邮件确认:

确认

Emails conflict:电子邮件冲突:

冲突

Output:输出:

输出

Note:笔记:

  • This approach doesn't check your input before the submission.这种方法在提交之前不会检查您的输入。 It just removes the last response afterwards IF there have been conflicts with the previous slot timings to that one.如果与之前的时隙时序发生冲突,它只会在之后删除最后一个响应。
  • Also, the one who sent the response wouldn't know that his slot was confirmed or not, not unless you ask for his email in the form and send confirmation afterwards the checking (whether his submitted response was removed due to conflict, or approved due to it having no conflict)此外,发送回复的人不会知道他的位置是否被确认,除非您在表单中询问他的电子邮件并在检查之后发送确认(他提交的回复是否因冲突而被删除,或因没有冲突)
  • If you have a time slot of 9:00 - 10:00, it won't accept another response with 9:00 in it since (>=, <=) is inclusive.如果您有 9:00 - 10:00 的时间段,它不会接受包含 9:00 的另一个响应,因为 (>=, <=) 是包含在内的。 What you can do is to pick timeslots where starting has 1/31 minute (eg 9:01-10:00 , 8:31-9:30 ) or the ending slots has 59/29 minutes (eg 9:00-9:59 , 8:30-9:29 ).您可以做的是选择开始时间为 1/31 分钟(例如9:01-10:008:31-9:30 )或结束时间为 59/29 分钟(例如9:00-9:598:30-9:29 )。
  • If that is a hassle, then you need to adjust the conditional on checking conflicts.如果这很麻烦,那么您需要调整检查冲突的条件。 You should be able to figure it out.你应该能够弄清楚。

As @Cooper pointed out, it seems best that you create your own web app.正如@Cooper 指出的那样,您最好创建自己的网络应用程序。

After a few hours of work I've made a web app that will work for you using Google Apps Script.经过几个小时的工作,我制作了一个可以使用 Google Apps Script 为您工作的网络应用程序。 Here are the spreadsheet and script file. 是电子表格和脚本文件。

Server Side Codes:服务器端代码:

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;
  
}

Client Side Codes:客户端代码:

 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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM