這次練習的程式流程跟之前的一樣
都是以Google sheets作為資料庫,在Google Apps Script製作回傳資料的API,然後建立查詢頁面
查詢頁面可以嵌入網站、Google Site,也可以寫在Google Apps Script裡
第3種方式會用到Google Apps Script本身的函數來溝通前後端的資料傳遞
回到到主題
這次練習跟之前的差異是增加了核取方塊(Checkbox) 來選擇查詢的內容
核取方塊(Checkbok)和選項按鈕(Radio)的差別:
- 前者是可以複選、被選取的方塊如果再重複點選就會取消
- 後者是單選,一旦被選取,如果要取消的話,不是全部取消checked,就是要選其他的按鈕
因此,這次使用核取方塊(Checkbok)才能夠達成想要的效果
測試用電子信箱:[email protected]
裡面的資料:姓名、電子信箱、跟網址都是假的
See the Pen Demo Post-學習扶助-講師培訓-課前表單 V5-4 by 莊幸諺 (@trico109748007) on CodePen.
後端程式碼
前端程式碼會傳來兩個參數,1個是電子信箱、1個是資料表
因為多了一個資料表的參數,我想把個別的資料表資料存成獨立的1筆資料
所以程式碼會多了一層迴圈,程式碼#22-81
第1層迴圈,比對出對應的google sheets ID
比對接收的資料表參數的方式,我比較土炮,應該會有更好的方式
arr1[]存放的是資料表參數
arr2[]存放的是依據arr1[]資料表參數所對應的googlesheets ID
利用indexOf()取得傳來的參數在arr1[]的序號,而這個序號對應arr2[]就可以得到googlesheets的ID
再來是第2層迴圈,從google sheets中比對是否有對應的電子信箱
如果有的話就取出資料
最後傳出的資料型態就會變成2層資料結構
[{course:{dataload:{}, dataload:{},……}},{course:{dataload:{}, dataload:{}, ……}}…]
由於部分資料表會有google drive的連結
因此在#53多了一個 if 來判斷 search(/drive.google.com/i) 是否 >0 ( i 表示不分大小寫)
如果>0,表示字串內帶有drive.google.com,也就是超連結,因此加上<a>~~</a>標籤
為了避免如果有2個連結接續再一起,</a>後面多了1 個空格
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
function doPost(e) { Logger.log(e); //取得參數 var params = e.parameter; var mailID = params.mailID;// console.log(mailID); var cID= params.cID; console.log(cID); var arryC = cID.split(","); console.log(arryC[0]); var arr1 =["c0101","c0102","c02","ch01","ch02","en01","en02","ma01","ma02"]; var arr2 =["1fuCeX0Frf_N1avskAaCZ8CZ_QPjpVmzt-MyLfmQ-tCU","1Or0-pD7GBI9icsXpGB5275o0hxuyZiBBGJ__0kXii6g","1GVha6hSEvntglGnTM3iO2tZqli70T3Q0zeg3cpI1aHE","1id-dB13xyx8rpBBNPZ6mEUvz25Y60p6AfWpW2E7oBrQ","1_2zCPSrxUyKzeVwi60DTFDM_8Zw_HRfSbzxQxMARmKE","12IZpoyma-SpbLWjUqIWsdivTMPGDJFBbu-rGsr0gG9U","1h4BO_5oiyE8uKgL84-iwEcP-cElkM7QxyLs73gfOSYU","1cYIy0Ojytx-F5yFhQnoc-ggmEiFdbsAlz5kr7J22-Ws","1oi8TLFDbsX_Q7YPakbheE7VAPI272SEyQkwpsWUm0kw"]; var dataAll = [];//用來存資料 for(var cc= 0; cc < arryC.length ; cc++){ var r =arr1.indexOf(arryC[cc]); //console.log(r); var sId = arr2[r]; //console.log(sId); ///* var Sheet = SpreadsheetApp.openById(sId).getSheets()[0]; var LastRow = Sheet.getLastRow(); var LastColumn = Sheet.getLastColumn(); var data = [];//用來存資料 // 取得全部資料 var listAll = Sheet.getSheetValues(1, 1, LastRow, LastColumn); //console.log( listAll[0]); //存標題 var listA =[]; for(var j=0; j < listAll[0].length ; j++){ listA.push(listAll[0][j]); } console.log(listA); //[listAll[0][0],listAll[0][1],listAll[0][2],listAll[0][3],listAll[0][4]]; data.push({dataload: listA }) //第1列是標題,序號由0開始,設定JSON格式{dataload: listAll[0]} //console.log(data); for(var i = 1; i < listAll.length; i++){ //第2列才是資料,序號由0開始 if(listAll[i][1] == mailID){ //電子信箱在第2欄,序號由0開始 var listOne =[]; for(var k=0; k < listAll[0].length ; k++){ if( listAll[i][k].toString().search(/drive.google.com/i) > 0){ var rr= listAll[i][k].split(","); //console.log(rr[0]); //console.log(rr[1]); if(rr.length >0){ var nHref =""; for(var m =0 ; m < rr.length ; m++){ nHref += "<a href='" + rr[m].trim() +"' target='_blank'>" + rr[m].trim() + "</a> "; } console.log("nHref"); console.log(nHref); listAll[i][k] =nHref; }else{ listAll[i][k] = "<a href='" + listAll[i][k]+"' target='_blank'>"+ listAll[i][k] +"</a>"; } //console.log(listAll[i][k] ); listOne.push(listAll[i][k]); }else{ listOne.push(listAll[i][k]); } } // [listAll[i][0], listAll[i][1], listAll[i][2], listAll[i][3],listAll[i][4]] data.push({dataload: listOne}); //寫入資料 } } dataAll.push({course:data}); } //顯示資料 // Logger.log(data); Logger.log(dataAll); //將資料存成JSON格式並回傳 //結果不同 return ContentService.createTextOutput(JSON.stringify(dataAll)).setMimeType(ContentService.MimeType.JSON); //物件 //return ContentService.createTextOutput(JSON.stringify(dataAll)); //字串 //*/ } |
前端程式碼
Html
checkbox依據課程種類設定對應的value值,這樣後續的程式才能夠知道是選了哪個選項
送出按鈕執行sender(),處理要傳到searchData()的參數
清除資料按鈕執行cleanAll()
<dialog>如果沒有填寫電子信箱或勾選項目就會出現提醒視窗,這個檢查的程式在sender()裡
這邊要留意的是<dialog>在JavaScript的執行方式比較簡單
但是這個練習抓取DOM的方式都是使用jQuery,而這樣得到的是jQuery物件
所以要將jQuery轉成JavaScript物件
var infoModal = $("#infoModal").get(0);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<div id="d1"> <label>電子信箱:<input id="mailID" type="text" /></label><br /><br /> <label>查詢填寫紀錄</label><br /> <label><input type="checkbox" name="courses1" value="c0101" />共同課程一 :低成就學生心理特質、學習動機及教學經營實務案例</label> <label><input type="checkbox" name="courses1" value="c0102" />共同課程一 :數位資源融入學習扶助教學知能</label><br /> <label><input type="checkbox" name="courses2" value="c02" />共同課程二 :科技化評量測驗結果應用</label><br /> <label><input type="checkbox" name="courses3" value="ch01" />分科課程 :國中國語文</label> <label><input type="checkbox" name="courses3" value="ch02" />分科課程 :國小國語文</label><br /> <label><input type="checkbox" name="courses3" value="en01" />分科課程 :國中英語文</label> <label><input type="checkbox" name="courses3" value="en02" />分科課程 :國小英語文</label><br /> <label><input type="checkbox" name="courses3" value="ma01" />分科課程 :國中數學  </label> <label><input type="checkbox" name="courses3" value="ma02" />分科課程 :國小數學</label> </div> <div id="d2"> <input name="search" id="sender" onclick="sender();" type="button" value="送出" /> <input name="clean" id="cleaner" onclick="cleanAll();" type="button" value="清除資料" /> </div> <span id="search_status"></span> <dialog id="infoModal"> <p>請輸入查詢資訊!!</p> <button id="close">關閉視窗</button> </dialog> |
Css
比較需要留意的是checbox或者radio都會有預設樣式
如果要改為自訂樣式的話
必須加上 appearance: none;
JavaScript
Function searchData()的修改
主要是在#108-155也是多了一層迴圈來處理後端回傳的資料
其實就是對應後端程式組合資料的方式,再拆解重新組合
#196-255,因為之前用radio來設計選項
而為了達成重複點選就取消的功能,所使用的程式碼
值得留意的是如果要綁定DOM事件的話,程式碼要在window.load之後再綁定
否則就會因為抓取不到對應的DOM而產生錯誤
以及radio在點取的當下,其狀態仍是checked false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
var dateReviver = function (key, value) { //將日期字串轉為日期資料型態 //console.log("key", key); //console.log("value", value); var a; if (typeof value === "string") { a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec( value ); //比對是否符合日期型態 //console.log(a); if (a) { var dataString = new Date( Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]) ); //console.log("dataString", dataString); var weekday = new Array(6); weekday[0] = "日"; weekday[1] = "一"; weekday[2] = "二"; weekday[3] = "三"; weekday[4] = "四"; weekday[5] = "五"; weekday[6] = "六"; var hour = dataString.getHours(); var min = dataString.getMinutes(); var sec = dataString.getSeconds(); // 轉成字串,如果低於10,前面加上'0' var hourString = hour < 10 ? "0" + hour : "" + hour; var minString = min < 10 ? "0" + min : "" + min; var secString = sec < 10 ? "0" + sec : "" + sec; var formatted_date = dataString.getFullYear() + "/" + (dataString.getMonth() + 1) + "/" + dataString.getDate() + "(" + weekday[dataString.getDay()] + ")" + " " + hourString + ":" + minString + ":" + secString; return formatted_date; } } return value; }; function searchData(mailID, cID) { console.log("searchData-", mailID, cID); var arryC = cID.split(","); console.log(arryC[0]); var arr1 = [ "c0101", "c0102", "c02", "ch01", "ch02", "en01", "en02", "ma01", "ma02" ]; var arr2 = [ "「共同課程一:低成就學生心理特質、學習動機及教學經營實務案例」", "「共同課程一:數位資源融入學習扶助教學知能」", "「共同課程二:科技化評量測驗結果應用」", "「分科課程:國中國語文」", "「分科課程:國小國語文」", "「分科課程:國中英語文」", "「分科課程:國小英語文」", "「分科課程:國中數學」", "「分科課程:國小數學」" ]; var cName = []; for (var cc = 0; cc < arryC.length; cc++) { var r = arr1.indexOf(arryC[cc]); //console.log(r); cName[cc] = arr2[r]; console.log(cName[cc]); } var sender = $("#sender"); var cleaner = $("#cleaner"); sender.attr("disabled", true); sender.val("搜尋中"); cleaner.attr("disabled", true); ///* $.ajax({ url: "https://script.google.com/macros/s/AKfycbxSf8TUnF-g62I7foCiNOjNvHFL1TK9Kw2PDf9IF5JQLfGEQa13yHyPaVC4hSk6ZFW1/exec", //Demo Post-學習扶助-講師培訓-課前表單 V5 method: "POST", data: { mailID: mailID, cID: cID }, success: function (e) { sender.attr("disabled", false); sender.val("送出"); cleaner.attr("disabled", false); var result = e; //console.log(typeof result); //object var obj = JSON.parse(JSON.stringify(result, dateReviver)); //解析json字串為json物件形式,dateReviver將日期字串轉為日期資料型態 //console.log(typeof obj); var html = ""; for (var m = 0; m < obj.length; m++) { console.log(obj[m]); console.log(cName[m]); if (obj[m].course.length == 1) { //只有1筆(標題)代表查不到資料 html += "<h3>" + (m + 1) + "-" + cName[m] + ":查無資料<h3>"; $("#search_status").html(html); //寫入Html //alert('查無資料'); $("#mailID").val(""); $('input[type="checkbox"]').prop("checked", false); } else { // // html += "<h3>" + (m + 1) + "-" + cName[m] + "</h3>"; html += '<div class="table"><div class="table-tr">'; //取出標題 for (var k = 0; k < obj[m].course[0].dataload.length; k++) { html += '<div class="table-th">' + obj[m].course[0].dataload[k] + "</div>"; } html += "</div>"; //<div class="table-tr"><div class="table-th">填寫日期</div><div class="table-th">電子信箱</div><div class="table-th">姓名</div><div class="table-th">服務單位</div><div class="table-th">職稱</div></div>'; //將資料寫出在Html表格,配合2次迴圈讀取每1筆資料內的所有資料 // for (var i = 1; i < obj[m].course.length; i++) { //所有筆數的資料跑迴圈 html += '<div class="table-tr">'; // for ( var j = 0; j < obj[m].course[i].dataload.length; j++ //每1筆資料內的所有資料,dataload對應回傳的JSON格式 ) { html += '<div class="table-td">' + obj[m].course[i].dataload[j] + "</div>"; } html += "</div>"; } html += "</div>"; // $("#search_status").html(html); //寫入Html $("#mailID").val(""); $('input[type="checkbox"]').prop("checked", false); } } } }); //*/ } // // function sender() { var courses = []; $('input[type="checkbox"]:checked').each(function (i) { courses.push($(this).val()); //console.log($(this).val()); //console.log(i); }); //console.log("sender"); console.log(courses.toString()); var email = $('#mailID').val(); if (courses.toString() == "" || email == "") { console.log("err"); //window.alert("請確認查詢資訊"); //var infoModal = document.getElementById("infoModal"); var infoModal = $("#infoModal").get(0); //重要 https://www.fooish.com/jquery/selectors.html var closeD = $("#close"); infoModal.show(); closeD.on("click", function () { console.log("close"); infoModal.close(); }); } else { $("#search_status").html(""); searchData(email, courses.toString()); } } // function cleanAll() { $("#search_status").html(""); $("#mailID").val(""); $('input[type="checkbox"]').prop("checked", false); } // /* $(document).ready(function() { //重要 $('input[type="radio"]').on("click", function() { //绑定click 事件 //var courses1 = $("input[type=radio]:checked").val(); //console.log("courses1"); //console.log($("input[type=radio]:checked").data("checked")); var $radio = $(this); //console.log($radio.data("checked")); if ($radio.data("checked") == true) { $radio.prop("checked", false); $radio.data("checked", false); //console.log("then"); //console.log($radio.data("checked")); } else { $radio.prop("checked", true); $radio.data("checked", true); //console.log("else"); //console.log($radio.data("checked")); } //console.log($radio.data("checked")); //var courses2 = $("input[type=radio]:checked").val(); //console.log("courses2"); //console.log($("input[type=radio]:checked").data("checked")); }); // });*/ |