วิธีใช้ Google Form ส่งข้อความเข้า LINE Notify

ขั้นตอนต่อไปนี้จะข้ามส่วนของรายละเอียดบางอย่างไป ซึ่งก่อนจะทำตรงนี้ควรจะรู้แล้วว่า LINE Notify ใช้ทำอะไร และ Access Token จะเอามาจากไหน แต่จะพยายามอธิบายให้ครอบคลุมที่สุดก็แล้วกัน

Update: 2019/09/04
เพิ่มวิธีแก้ไขหากทดสอบแล้วติดปัญหา TypeError: ไม่สามารถเรียก Method “getItemResponses” ของ undefined หรือ TypeError: Cannot call method “getItemResponses” of undefined.  [Link]

Update: 2019/06/10
ในท้ายบทความได้เพิ่มคำอธิบายเรื่องการส่งข้อมูลหลายกล่องข้อมูล (คอลั่ม) พร้อมกับ code ที่วนลูปข้อมูลทุกกล่อง เพื่อความสะดวกในการส่งข้อมูลในรูปแบบเดิม [Link]

Start Google Form

วิธีสร้างก็ง่ายแสนง่าย เข้าไปที่ https://docs.google.com/forms จากนั้น คลิกตรงเครื่องหมาย + ตามภาพ

จะได้ form หน้าตาแบบนี้มา

แก้ไขตามสะดวกเลย ตัวอย่างเอาแบบนี้แล้วกัน จะลองส่งข้อความคลิกที่รูปตา “👁”

พิมพ์ข้อความอะไรก็ได้ แล้ว กด Submit โลด

กลับไปหน้า Form ของเราใน tab แรก มันก็จะมี RESPONSES เข้ามา เมื่อคลิกดูก็จะพบข้อความที่เราเพิ่งพิมพ์ไปเมื่อตะกี้

Start Script Editor

คลิกที่ จุด 3 จุด ด้านขวาบน แล้วเลือก <> Script Editor เพื่อจะใส่ code

จะพบหน้าเปล่าๆ ที่ไม่คุ้นเคย ตรงนี้แหละที่เราจะมาใส่ code ให้มันส่งข้อความจาก Google Form ไปยัง LINE กลุ่ม หรือ chat ส่วนตัวของเรา ซึ่งเพื่อเป็นการรวดเร็ว ไม่ต้องพิมพ์ เอา code ด้านล่างไปใส่ได้เลยจ้า

function onFormSubmit() {

    var msg = "Hello World!";
        sendLineNotify(msg);
}

function sendLineNotify(message) {

    var token = ["ACCESS TOKEN"]; //ใส่ access token ที่ใช้งาน
    var options = {
        "method": "post",
        "payload": "message=" + message,
        "headers": {
            "Authorization": "Bearer " + token
        }
    };

    UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}

อย่าลืมใส่ ACCESS TOKEN เด้อ ถ้ายังไม่ได้สร้าง กดที่นี่ https://notify-bot.line.me/my/

เมื่อ copy code ไปใส่จากนั้นก็กด Save ตรงรูปแผ่นดิส 💾 แล้วตั้งชื่ออะไรก็ได้ตามใจ จากนั้นกด OK

จากนั้นมาลอง Run ทดสอบดูว่าตอนนี้ function ที่เราก๊อบมา สามารถทำงานได้แล้วหรือยัง โดยกด ตรง Select function จากนั้นเลือก onFormSubmit

จากนั้นกดที่เครื่องหมาย Run ▶ ซึ่งมันจะมีการขอ permission จาก Google Account นิดหน่อย กดๆไปเถอะ

หลังจาก Allow Permission แล้ว function ที่เรากดมันก็จะทำงานทันที ถ้าได้รับข้อความเข้าแบบนี้ก็ถือว่าผ่าน

ต่อไปเราจะดึงข้อมูลจาก google form ออกมาส่ง โดยนำ form ID ที่อยู่บน URL มาใส่ใน code ด้านล่างนี้ครับ

Form ID คือส่วนที่เป็นตัวหนา
https://docs.google.com/forms/d/1-IjQ0uX-j3bAZmBmXnixl74vtM876Xsq-_faxJ5eQ9U/edit

function onFormSubmit() {
    
    var form = FormApp.openById('FORM_ID');
    var fRes = form.getResponses();

    var formResponse = fRes[fRes.length - 1];
    var itemResponses = formResponse.getItemResponses();

   var msg = 'New Message!'
     + ' \n' + itemResponses[0].getItem().getTitle() + ': ' + itemResponses[0].getResponse() 
        sendLineNotify(msg);
    //  Logger.log(msg)
}

function sendLineNotify(message) {

    var token = ["ACCESS TOKEN"];
    var options = {
        "method": "post",
        "payload": "message=" + message,
        "headers": {
            "Authorization": "Bearer " + token
        }
    };

    UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}

เสร็จแล้วกด Run เลยจ้าาา (มันจะถาม Permission อีกรอบนึง เพราะว่าคราวนี้มีการขอเข้าไปจัดการข้อมูลด้วย)

เสร็จแล้วถ้าข้อความยังไม่ส่งเข้า LINE ให้กด Run อีกครั้ง

ถ้าใครทำตามภาพได้ แสดงว่า Function ทำงานได้แล้ว ต่อไปเราจะสร้าง Trigger เพื่อให้มัน ดัก Event ที่เกิดขึ้น เพื่อให้มาเรียก function นี้ทำงาน เพราะเราคงไม่มีเวลานั่งกด Run เองทั้งวัน และจุดประสงค์ของวันนี้คือ เมื่อมีคน Submit ข้อมูลใหม่ มันจะต้องเอาข้อมูลนั้นมาแจ้งเตือนใน LINE

TypeError: Cannot call method

หากกด Run แล้วติดปัญหา
TypeError: Cannot call method “getItemResponses” of undefined. 

เนื่องจากท่านไม่ได้ submit ข้อมูลตามขั้นตอนนี้ (submit) ทำให้ script มันเจอแต่ตารางเปล่า ๆ จึงแจ้งกลับมาว่า … of undefined

Start Project’s Trigger

ขั้นตอนนี้เราจะเรียก function ให้ทำงานอัตโนมัติด้วยการสร้าง Trigger ให้เลือกที่เมนู Edit > Current project's triggers

จะเปิดหน้าต่างใหม่ขึ้นมา (Design เดิมมันเป็นแบบ Box Overlay ใช้งานในหน้าเดียวกับ Script Editor เลยไม่ได้แยกแบบนี้) ให้กดไปที่ Add Trigger ด้านล่างขวา

จะมี dialog box ขึ้นมา ให้เลือกตามภาพเลยก็ได้ จากนั้นกด Save

  • Choose which function to run : ในส่วนนี้จะให้เลือก function สำหรับเรียกใช้งานผ่าน trigger
  • Choose which deployment should run : จะ deploy trigger ไว้ที่ไหน เท่าที่เห็นตอนนี้มีแต่ head อย่างเดียว
  • Select event source : แหล่งที่มา มีให้เลือกว่า
    • From form : จากฟอร์มที่เราสร้าง
    • Time-driver : จากช่วงเวลาที่เรากำหนด เช่น ทุกชั่วโมง, วัน เดือน หรือ แค่วันใดวันหนึ่ง เป็นต้น
    • From calendar : จากปฏิทิน (ยังไม่ได้ลอง ไม่รู้มันเชื่อมยังไงเหมือนกัน)
  • Select event type : On Open หรือ On form submit
  • Failure notification settings : การแจ้งเตือนเมื่อมันบกพร่อง หรือ มีปัญหา เลือก immediately ก็ได้ ให้มันเตือนทันที (มันจะส่งเข้า Gmail ของเจ้าของ Script หรือ form นั้น)

กด Save แล้วรอ จนกว่ามันจะขึ้นรายการแบบนี้ แสดงว่า trigger ที่สร้างเสร็จแล้วพร้อมทำงาน

กลับมาหน้า Form สำหรับกรอกข้อความ ลองส่งได้เลย

ดูผลงานกัน จบม่ะ?

สรุปครับ

สิ่งที่คุณจะต้องเอาไปต่อยอดคือ Google Form API ที่ผมไม่ได้พูดถึง ผมใช้ FormApp.openById เนื่องจากเคยใช้ SpreadsheetApp.openById แล้วปัญหาคือมันจะมีข้อมูลเกินมา หรือมันไม่ยอมเอารายการที่ submit ล่าสุดมาส่ง

หากต้องการส่งมากกว่า 1 ข้อความ ก็ให้ใช้ loop เอาครับ อ่านค่าจาก getResponses() มาดู ซึ่งมันมี function สำหรับแสดง log คล้ายๆ console.log น่ะ ชื่อว่า Logger.log(ข้อความที่จะแสดงผล) สำหรับเอาไว้ debug code ที่เราเขียน เวลากด Run แล้วมันจะเอาไปเก็บไว้ใน log โดยวิธีการเปิดดูก็กด Ctrl + Enter หรือ เลือกที่ View > Logs ก็ได้เช่นกัน หน้าตามันก็จะออกมาแบบนี้

UrlFetchApp.fetch : Fetch resources and communicate with other hosts over the Internet. ตัวทีเด็ดที่ใช้ทอดสะพานรักครั้งนี้

getResponse() : Gets the answer that the respondent submitted. For most types of question items, this returns a String. ลองดูข้อมูลที่ได้ในนี้ครับ มันมีทุกอย่างแล้ว แต่เราต้องหาวิธีเอามันออกมาเท่านั้น

แถม VDO ให้ดู

https://www.facebook.com/thanikuls/videos/10155578276993257/

อธิบายเพิ่มเติม : การส่งข้อความในกล่องที่ 2

function onFormSubmit() {
    
    var form = FormApp.openById('FORM_ID');
    var fRes = form.getResponses();

    var formResponse = fRes[fRes.length - 1];
    var itemResponses = formResponse.getItemResponses();

   var msg = 'New Message!'
     + ' \n' + itemResponses[0].getItem().getTitle() + ': ' + itemResponses[0].getResponse() 
        sendLineNotify(msg);
    //  Logger.log(msg)
}

ใน function onFormSubmit() จะมี ตัวแปร itemResponses ที่เราดึงค่ามาจาก form ที่สร้างไว้ ส่งที่ได้มาจะเป็น array ( array คือข้อมูลที่ถูกเก็บอยู่เป็นชั้นๆ ตามลำดับเลข เริ่มจาก 0,1,2…,n) ซึ่งใน array นี้ ก็มีชื่อที่เรานำมาใช้ดังนี้

itemResponses[0].getItem().getTitle()

itemResponses[0] คือ ชุดข้อมูลในละดับแรก
. getItem().getTitle() คือ function เรียกหัวตารางของ item
itemResponses[0].getResponse() คือ function เรียกข้อมูลชุดแรก (column แรก)

ข้อมูลชุดต่อไป เราจะใช้เลข 1 ดังนั้นการเรียกข้อมูลก็จะใช้แบบนี้

itemResponses[1].getItem().getTitle()
itemResponses[1].getResponse()

ทีนี้ก็สามารถใส่เลข 2 3 4 ไปได้เรื่อยๆ ง่ายมั้ย?

function onFormSubmit() {

    var form = FormApp.openById('FORM_ID');
    var fRes = form.getResponses();

    var formResponse = fRes[fRes.length - 1];
    var itemResponses = formResponse.getItemResponses();

    var msg = 'New Message!' +
        ' \n' + itemResponses[0].getItem().getTitle() + ': ' + itemResponses[0].getResponse() +
        ' \n' + itemResponses[1].getItem().getTitle() + ': ' + itemResponses[1].getResponse() + 
        ' \n' + itemResponses[2].getItem().getTitle() + ': ' + itemResponses[2].getResponse()

    sendLineNotify(msg);

}

แต่ถ้าขี้เกียจ และต้องการความรวดเร็ว ในการแสดงข้อมูลซ้ำรูปแบบเดิมๆ เราก็ใช้แบบนี้ครับ เอา itemResponses มาวนลูป ตามภาพนี้ ผลลัพท์ที่ได้เหมือนกัน แต่เขียน code สั้นลง

function onFormSubmit() {

    var form = FormApp.openById('FORM_ID');
    var fRes = form.getResponses();

    var formResponse = fRes[fRes.length - 1];
    var itemResponses = formResponse.getItemResponses();
    var msg = 'New Message!';

    for (var i = 0; i < itemResponses.length; i++) {
        msg += ' \n' + itemResponses[i].getItem().getTitle() + ': ' + itemResponses[i].getResponse();
    }

    sendLineNotify(msg);
}

itemResponses.length เป็นจำนวนของกล่องข้อความที่เราเพิ่มไว้ใน Google Form โดย function จะเก็บในรูปแบบ array ที่เริ่มต้นตำแหน่งแรกด้วยเลข 0 ด้วยเหตุนี้ เราจึงเริ่มตั้งตัวแปร i = 0

Update 2023-04-18

เพิ่งรู้ว่าเราสามารถใช้ const, let และ arrow function บน google app script ได้แล้ว [V8 Runtime Overview]

const onFormSubmit = () => {

  const form = FormApp.openById('FORM_ID');
  const fRes = form.getResponses();

  const formResponse = fRes[fRes.length - 1];
  const itemResponses = formResponse.getItemResponses();
  let msg = 'New Message!';

  for (let i = 0; i < itemResponses.length; i++) {
    if (itemResponses[i].getResponse() < 2 || itemResponses[i].getResponse() > 8) {
      msg += ' \n' + itemResponses[i].getItem().getTitle() + ': ' + itemResponses[i].getResponse();
    }
  }

  sendLineNotify(msg);
}

const sendLineNotify = (message) => {

  let token = ["ACCESS_TOKEN"];
  let options = {
    "method": "post",
    "payload": "message=" + message,
    "headers": {
      "Authorization": "Bearer " + token
    }
  };

  UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}