รีเฟรชข้อมูลที่ดึงมาโดยฟังก์ชันที่กำหนดเองใน Google Sheet


92

ฉันได้เขียนสคริปต์ Google Apps ที่กำหนดเองซึ่งจะรับidและดึงข้อมูลจากบริการเว็บ (ราคา)

ฉันใช้สคริปต์นี้ในสเปรดชีตและใช้งานได้ดี ปัญหาของฉันคือราคาเหล่านี้เปลี่ยนแปลงและสเปรดชีตของฉันไม่ได้รับการอัปเดต

ฉันจะบังคับให้เรียกใช้สคริปต์อีกครั้งและอัปเดตเซลล์ได้อย่างไร (โดยไม่ต้องข้ามแต่ละเซลล์ด้วยตนเอง)


1
ใช่นี่คือคำอธิบายที่ฉันทำกับสิ่งนี้stackoverflow.com/questions/9022984/…
Henrique G. Abreu

ฉันอ่านคำอธิบายของคุณซึ่งเป็นส่วนหนึ่งของงานวิจัยของฉัน มีประโยชน์มากขอบคุณ ฉันเพิ่มลิงค์ไปยังคำตอบของฉัน
tbkn23

สำหรับผู้ที่เผชิญหน้าที่คล้ายกัน (ตามที่กำหนดและตรรกะ แต่บางครั้งโชคร้าย) ลักษณะการทำงานก็อาจจะช่วยให้ไป upvote คำขอคุณลักษณะนี้ใน Google ติดตามปัญหา: issuetracker.google.com/issues/36763858
Timothy Johns

นี่คือคำตอบง่ายๆที่ฉันทำ
Aerials

วิธีแก้ปัญหาจริง: stackoverflow.com/a/56802017และstackoverflow.com/a/61946592
TheMaster

คำตอบ:


92

โอเคดูเหมือนว่าปัญหาของฉันคือ google ทำงานในลักษณะแปลก ๆ - มันจะไม่เรียกใช้สคริปต์อีกครั้งตราบใดที่พารามิเตอร์สคริปต์คล้ายกัน แต่จะใช้ผลลัพธ์ที่แคชจากการรันก่อนหน้านี้ ดังนั้นจึงไม่เชื่อมต่อกับ API อีกครั้งและไม่เรียกราคาซ้ำ แต่จะส่งคืนผลลัพธ์ของสคริปต์ก่อนหน้านี้ที่แคชไว้

ดูข้อมูลเพิ่มเติมที่นี่: https://code.google.com/p/google-apps-script-issues/issues/detail?id=888

และที่นี่: สคริปต์สรุปข้อมูลไม่อัปเดต

วิธีแก้ปัญหาของฉันคือเพิ่มพารามิเตอร์อื่นให้กับสคริปต์ของฉันซึ่งฉันไม่ได้ใช้ด้วยซ้ำ ตอนนี้เมื่อคุณเรียกใช้ฟังก์ชันด้วยพารามิเตอร์ที่แตกต่างจากการเรียกก่อนหน้านี้จะต้องรันสคริปต์อีกครั้งเนื่องจากผลลัพธ์ของพารามิเตอร์เหล่านี้จะไม่อยู่ในแคช

ดังนั้นเมื่อใดก็ตามที่ฉันเรียกใช้ฟังก์ชันสำหรับพารามิเตอร์พิเศษฉันจะส่ง "$ A $ 1" ฉันยังสร้างรายการเมนูที่เรียกว่าการรีเฟรชและเมื่อฉันเรียกใช้มันจะใส่วันที่และเวลาปัจจุบันเป็น A1 ดังนั้นการเรียกสคริปต์ทั้งหมดที่มี $ A $ 1 เป็นพารามิเตอร์ที่สองจะต้องคำนวณใหม่ นี่คือรหัสบางส่วนจากสคริปต์ของฉัน:

function onOpen() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  var entries = [{
    name : "Refresh",
    functionName : "refreshLastUpdate"
  }];
  sheet.addMenu("Refresh", entries);
};

function refreshLastUpdate() {
  SpreadsheetApp.getActiveSpreadsheet().getRange('A1').setValue(new Date().toTimeString());
}

function getPrice(itemId, datetime) {
  var headers =
      {
        "method" : "get",
        "contentType" : "application/json",
        headers : {'Cache-Control' : 'max-age=0'}
      };

  var jsonResponse = UrlFetchApp.fetch("http://someURL?item_id=" + itemId, headers);
  var jsonObj = eval( '(' + jsonResponse + ')' );
  return jsonObj.Price;
  SpreadsheetApp.flush();
}   

และเมื่อฉันต้องการใส่ราคาของสินค้าที่มี ID 5 ในเซลล์ฉันใช้สูตรต่อไปนี้:

=getPrice(5, $A$1)

เมื่อต้องการรีเฟรชราคาฉันเพียงแค่คลิกรายการเมนู "รีเฟรช" -> "รีเฟรช" โปรดจำไว้ว่าคุณต้องโหลดสเปรดชีตซ้ำหลังจากที่คุณเปลี่ยนonOpen()สคริปต์


4
ทำไมไม่ใช้ now () เป็นพารามิเตอร์เพิ่มเติม
ขั้นสูง

5
คุณจะเห็นเช่นเดียวกับฟังก์ชันของฉันจะไม่ได้รับการประเมินซ้ำเนื่องจากพารามิเตอร์ไม่ได้เปลี่ยนแปลง (เช่นค่าของเซลล์) ตอนนี้ () จะไม่ได้รับการประเมินซ้ำเนื่องจากไม่มีพารามิเตอร์ดังนั้นจึงเป็นค่าที่ส่งคืน ไม่เปลี่ยนแปลงดังนั้นพารามิเตอร์ของฟังก์ชันของฉันจะไม่เปลี่ยนแปลง นอกจากนี้การใช้ now () จะทำให้ฟังก์ชันของฉันประเมินซ้ำตลอดเวลาซึ่งค่อนข้างหนักเมื่อพิจารณาว่ามีการเรียก HTTP หลายครั้ง ...
tbkn23

2
หาดี ฉันมีปัญหานี้ขณะใช้ช่วงที่ตั้งชื่อเป็นอินพุต จากคำตอบของคุณฉันพบว่าบ่อยครั้งที่ดีพอที่จะส่งผ่านผลรวมจำลองในช่วงของอินพุตเช่นเดียวกับ "ผลรวม (B: D)" โดยที่แถว BD อยู่ในช่วงที่ฟังก์ชันกำหนดเองค้นหา การเปลี่ยนเซลล์ใด ๆ จะทำให้ผลรวมเปลี่ยนและฟังก์ชันที่กำหนดเองจะรีเฟรช อย่างไรก็ตามดูเหมือนว่าฟังก์ชันที่กำหนดเองจะไม่จำเป็นต้องประกาศพารามิเตอร์ที่ละเว้น
Shawn Hoover

1
น่าเสียดายที่นี่ยังคงเป็นทางออกที่ดีที่สุดที่ฉันพบกับปัญหานี้ แทนที่จะอนุญาตให้เราปิดการใช้งานแคชสำหรับการเรียกใช้ฟังก์ชันเฉพาะเราจะเพิ่มสิ่งที่จัดเก็บไว้ในแคชโดยพลการเพื่อให้แน่ใจว่าเราจะไม่ได้รับค่าแคช ... ยังคงขอบคุณสำหรับโพสต์
GrayedFox

ลองใช้พารามิเตอร์สำหรับฟังก์ชันที่กำหนดเองของคุณดังตัวอย่างนี้
Aerials

33

ฉันรู้ว่านี่เป็นคำถามเก่าไปหน่อย แต่วิธีนี้ไม่ต้องการการดำเนินการใด ๆ ของผู้ใช้ยกเว้นทำการเปลี่ยนแปลง

สิ่งที่ฉันทำคล้ายกับ tbkn23

ฟังก์ชันที่ฉันต้องการประเมินใหม่มีพารามิเตอร์พิเศษที่ไม่ได้ใช้คือ $ A $ 1 ดังนั้นการเรียกใช้ฟังก์ชันคือ

=myFunction(firstParam, $A$1)

แต่ในรหัสลายเซ็นของฟังก์ชันคือ

function myFunction(firstParam)

แทนที่จะมีฟังก์ชั่นรีเฟรชฉันใช้ฟังก์ชัน onEdit (e) แบบนี้

function onEdit(e)
{
   SpreadsheetApp.getActiveSheet().getRange('A1').setValue(Math.random());
}

ฟังก์ชันนี้จะถูกทริกเกอร์ทุกครั้งที่มีการแก้ไขเซลล์ใด ๆ ในสเปรดชีต ตอนนี้คุณแก้ไขเซลล์แล้วจำนวนสุ่มจะถูกวางไว้ใน A1 ซึ่งจะรีเฟรชรายการพารามิเตอร์ตามที่ tbkn23 แนะนำทำให้ฟังก์ชันที่กำหนดเองได้รับการประเมินใหม่


5
ใช้งานได้ดี ข้อเสียคือประวัติการเลิกทำ (ctrl + z) ยุ่งเหยิง
จอน

1
เคล็ดลับที่ดีพร้อมข้อเสียที่น่ารำคาญขณะที่จอนชี้ให้เห็น ... ฉันหวังว่าใครบางคนจะปรับปรุงมัน :-)
Enissay

1
ข้อแม้เล็กและอวดดีกับคำตอบนี้ ในเหตุการณ์ที่ไม่น่าเป็นไปได้อย่างไม่น่าเชื่อ Math.random จะส่งคืนหมายเลขเดียวกันในโอกาสนั้นจะไม่อัปเดตเนื่องจากหมายเลขนั้นถูกแคชไว้แล้ว
Woody Payne

12

มันสายไปมากแล้วและฉันไม่รู้ว่ามันจะมีประโยชน์ แต่จริงๆแล้วมีการตั้งค่าที่คุณสามารถNOW()อัปเดตโดยอัตโนมัติได้

ป้อนคำอธิบายภาพที่นี่


1
NOW()เป็นฟังก์ชันในตัวไม่ใช่ฟังก์ชันที่กำหนดเอง
Rubén

@ Rubénจุดคือคุณอาจรวมถึง NOW () ฟังก์ชั่นในการทำงานที่กำหนดเองใด ๆ ที่คุณต้องการที่จะมีมันอัปเดต
Thaina

13
ในเวลานี้อาร์กิวเมนต์ของฟังก์ชันที่กำหนดเองควรถูกกำหนดขึ้นกล่าวอีกนัยหนึ่งคือพวกเขาไม่ได้รวม NOW () เป็นอาร์กิวเมนต์ ดูdeveloper.google.com/apps-script/guides/sheets/functions
Rubén

3
จะแสดงข้อผิดพลาดหากคุณพยายามใช้ NOW () ภายในฟังก์ชันที่กำหนดเอง
Stefano Giacone

6

หากฟังก์ชันที่กำหนดเองของคุณอยู่ภายในคอลัมน์ใดคอลัมน์หนึ่งเพียงแค่จัดลำดับสเปรดชีตของคุณตามคอลัมน์นั้น

การดำเนินการจัดลำดับบังคับให้มีการรีเฟรชข้อมูลซึ่งเรียกใช้ฟังก์ชันที่กำหนดเองของคุณสำหรับแถวทั้งหมดของคอลัมน์นั้นพร้อมกัน


1

นี่อาจเป็นกระทู้เก่าสุด ๆ แต่อาจมีประโยชน์สำหรับคนที่พยายามทำเช่นนี้เหมือนตอนนี้

การทำงานจากสคริปต์ของ Lexi ตามที่เป็นอยู่ดูเหมือนว่าจะไม่ทำงานกับชีตปัจจุบันอีกต่อไป แต่ถ้าฉันเพิ่มตัวแปรดัมมี่ลงในฟังก์ชันของฉันเป็นพารามิเตอร์ (ไม่จำเป็นต้องใช้มันในฟังก์ชันจริงๆ) มันจะแน่นอน บังคับให้ Google ชีตรีเฟรชหน้าอีกครั้ง

ดังนั้นการประกาศเช่น: function myFunction (firstParam, dummy) แล้วเรียกมันจะเป็นไปตามที่ได้รับการแนะนำ ที่ได้ผลสำหรับฉัน

นอกจากนี้หากเป็นความรำคาญสำหรับตัวแปรสุ่มที่จะปรากฏบนแผ่นงานทั้งหมดของคุณที่คุณแก้ไขวิธีแก้ไขง่ายๆในการ จำกัด ให้เหลือเพียงแผ่นเดียวมีดังนี้

function onEdit(e)
{
  e.source.getSheetByName('THESHEETNAME').getRange('J1').setValue(Math.random());
}

1
@ Rubénมันคล้ายกันมาก แต่มีความรำคาญดี แทนที่จะใช้แผ่นงานที่ใช้งานอยู่จะใช้ชื่อแผ่นงานที่กำหนดไว้ปรับปรุงประวัติของคุณ
Jonas D.

1

ตรรกะของสคริปต์:

  • ฟังก์ชันที่กำหนดเองจะไม่อัปเดตเว้นแต่จะมีการเปลี่ยนแปลงอาร์กิวเมนต์
  • สร้างทริกเกอร์ onChange เพื่อเปลี่ยนอาร์กิวเมนต์ทั้งหมดของฟังก์ชันที่กำหนดเองทั้งหมดในสเปรดชีตโดยใช้ textFinder

ตัวอย่างข้อมูล:

/*@customfunction*/
function sheetNames(e) {
  return SpreadsheetApp.getActive()
    .getSheets()
    .map(function(sheet) {
      return sheet.getName();
    });
}

/*Create a installable trigger to listen to grid changes on the sheet*/
function onChange(e) {
  if (!/GRID/.test(e.changeType)) return; //Listen only to grid change
  SpreadsheetApp.getActive()
    .createTextFinder('=SHEETNAMES\\([^)]*\\)')
    .matchFormulaText(true)
    .matchCase(false)
    .useRegularExpression(true)
    .replaceAllWith(
      '=SHEETNAMES(' + (Math.floor(Math.random() * 500) + 1) + ')'
    );
}

อ่าน:


1

ดังที่ระบุไว้ก่อนหน้านี้:

ฟังก์ชันที่กำหนดเองจะไม่อัปเดตเว้นแต่จะมีการเปลี่ยนแปลงอาร์กิวเมนต์

วิธีแก้ปัญหาที่เป็นไปได้คือการสร้างช่องทำเครื่องหมายในเซลล์เดียวและใช้เซลล์นี้เป็นอาร์กิวเมนต์สำหรับฟังก์ชันที่กำหนดเอง:

  1. สร้างช่องทำเครื่องหมาย: เลือกเซลล์ว่างเช่น [A1] ไปที่ [แทรก]> [ช่องทำเครื่องหมาย]
  2. ทำให้เซลล์นี้เป็นอาร์กิวเมนต์: =myFunction(A1)
  3. คลิกช่องทำเครื่องหมายเพื่อรีเฟรชสูตร

-3

หากคุณเขียนฟังก์ชันที่กำหนดเองและใช้ในสเปรดชีตของคุณเป็นสูตรทุกครั้งที่คุณเปิดสเปรดชีตหรือมีการแก้ไขเซลล์อ้างอิงใด ๆ สูตรจะคำนวณใหม่

หากคุณต้องการเพียงแค่จ้องดูสเปรดชีตและต้องการให้ค่าเปลี่ยนแปลงให้พิจารณาเพิ่มทริกเกอร์ตามกำหนดเวลาที่จะอัปเดตเซลล์ อ่านเพิ่มเติมเกี่ยวกับทริกเกอร์ที่นี่


10
นั่นจะดีมากยกเว้นว่าจะไม่ทำงาน ... การโหลดหน้าเว็บซ้ำจะไม่รีเฟรชค่า ยิ่งไปกว่านั้นการลบเซลล์และป้อนการเรียกใช้ฟังก์ชันเดิมอีกครั้งยังคงรักษาค่าเดิมไว้ ถ้าฉันเรียกฟังก์ชันเดียวกันจากเซลล์อื่นทุกประการมันจะแสดงค่าใหม่ แต่ไม่ได้อยู่ในเซลล์เก่า
tbkn23
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.