Segarkan data yang diambil oleh fungsi kustom di Google Spreadsheet

92

Saya telah menulis Skrip Google Apps khusus yang akan menerima iddan mengambil informasi dari layanan web (harga).

Saya menggunakan skrip ini dalam spreadsheet, dan berfungsi dengan baik. Masalah saya adalah harga ini berubah, dan spreadsheet saya tidak diperbarui.

Bagaimana saya bisa memaksanya untuk menjalankan kembali skrip dan memperbarui sel (tanpa memeriksa setiap sel secara manual)?

tbkn23.dll
sumber
1
Ya, inilah penjelasan yang saya lakukan untuk ini: stackoverflow.com/questions/9022984/…
Henrique G. Abreu
Saya membaca penjelasan Anda sebagai bagian dari penelitian saya. Sangat membantu, terima kasih. Saya menambahkan tautan ke jawaban saya.
tbkn23
Bagi mereka yang mengalami perilaku serupa (didefinisikan dan logis, tetapi terkadang tidak menguntungkan), mungkin ada gunanya untuk meningkatkan permintaan fitur ini di Google Issue Tracker: Issuetracker.google.com/issues/36763858 .
Timothy Johns
Inilah jawaban sederhana yang saya lakukan.
Aerials

Jawaban:

92

Oke, sepertinya masalah saya adalah Google berperilaku aneh - tidak menjalankan ulang skrip selama parameter skrip serupa, ia menggunakan hasil yang di-cache dari proses sebelumnya. Oleh karena itu, ia tidak terhubung kembali ke API dan tidak mengambil kembali harga, ia hanya mengembalikan hasil skrip sebelumnya yang di-cache.

Lihat info lebih lanjut di sini: https://code.google.com/p/google-apps-script-issues/issues/detail?id=888

dan di sini: Skrip untuk meringkas data yang tidak diperbarui

Solusi saya adalah menambahkan parameter lain ke skrip saya, yang bahkan tidak saya gunakan. Sekarang, ketika Anda memanggil fungsi dengan parameter yang berbeda dari panggilan sebelumnya, itu harus menjalankan kembali skrip karena hasil untuk parameter ini tidak akan ada di cache.

Jadi setiap kali saya memanggil fungsi tersebut, untuk parameter tambahan saya mengirimkan "$ A $ 1". Saya juga membuat item menu yang disebut refresh, dan ketika saya menjalankannya, itu menempatkan tanggal dan waktu saat ini di A1, maka semua panggilan ke skrip dengan $ A $ 1 sebagai parameter kedua harus dihitung ulang. Berikut beberapa kode dari skrip saya:

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

Dan ketika saya ingin memasukkan harga item dengan ID 5 di sel, saya menggunakan rumus berikut:

=getPrice(5, $A$1)

Ketika saya ingin menyegarkan harga, saya cukup mengklik item menu "Refresh" -> "Refresh". Ingatlah bahwa Anda perlu memuat ulang spreadsheet setelah Anda mengubah onOpen()skrip.

tbkn23.dll
sumber
4
mengapa tidak menggunakan now () sebagai parameter tambahan?
Lanjutan
5
Soalnya, seperti fungsi saya tidak akan dievaluasi ulang karena parameternya belum berubah (yaitu nilai sel), now () tidak akan dievaluasi ulang karena tidak memiliki parameter, maka nilai kembaliannya akan tidak berubah dan parameter fungsi saya tidak akan berubah. Juga, menggunakan now () akan menyebabkan fungsi saya mengevaluasi ulang sepanjang waktu yang agak berat mengingat itu menghasilkan beberapa panggilan HTTP ...
tbkn23
2
Temuan bagus. Saya mengalami masalah ini saat menggunakan rentang bernama sebagai masukan. Dengan menggunakan jawaban Anda, saya menemukan bahwa seringkali cukup baik untuk melewatkan jumlah dummy pada rentang input, seperti dalam "sum (B: D)", di mana baris BD berada dalam rentang yang dicari oleh fungsi kustom. Mengubah sel apa pun akan memicu jumlah untuk berubah dan fungsi kustom untuk menyegarkan. Ngomong-ngomong, tampaknya fungsi khusus bahkan tidak perlu mendeklarasikan parameter yang diabaikan.
Shawn Hoover
1
Sayangnya ini masih merupakan solusi terbaik yang saya temukan untuk masalah ini. Daripada Google hanya mengizinkan kami menonaktifkan cache untuk panggilan fungsi tertentu, kami secara sewenang-wenang meningkatkan apa yang disimpan di cache hanya untuk memastikan kami tidak mendapatkan nilai cache ... Tetap saja, terima kasih untuk posting,
GrayedFox
Coba gunakan parameter untuk fungsi kustom Anda seperti contoh ini
Aerials
33

Saya tahu ini adalah pertanyaan lama. Tetapi metode ini tidak memerlukan tindakan pengguna apa pun kecuali melakukan perubahan.

Apa yang saya lakukan mirip dengan tbkn23.

Fungsi yang ingin saya evaluasi ulang memiliki parameter ekstra yang tidak digunakan, $ A $ 1. Jadi panggilan fungsinya adalah

=myFunction(firstParam, $A$1)

Tapi di dalam kode, tandatangan fungsinya adalah

function myFunction(firstParam)

Alih-alih memiliki fungsi Refresh, saya telah menggunakan fungsi onEdit (e) seperti ini

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

Fungsi ini dipicu setiap kali ada sel dalam spreadsheet yang diedit. Jadi sekarang Anda mengedit sel, nomor acak ditempatkan di A1, ini menyegarkan daftar parameter seperti yang disarankan tbkn23, menyebabkan fungsi kustom dievaluasi ulang.

Sikat Lexi
sumber
5
Bekerja dengan baik. Sisi negatifnya adalah, urungkan (ctrl + z) riwayat kacau.
Jon
1
Trik bagus dengan sisi negatif yang menjengkelkan seperti yang ditunjukkan Jon ... Saya harap seseorang akan memperbaikinya :-)
Enissay
1
Peringatan kecil dan saksama dengan jawaban ini; dalam peristiwa yang sangat tidak mungkin, Math.random mengembalikan nomor yang sama, pada kesempatan itu ia tidak akan diperbarui, karena nomor tersebut telah di-cache.
Woody Payne
12

Ini sangat terlambat dan saya tidak tahu itu akan berguna tetapi sebenarnya ada pengaturan di sini Anda dapat melakukan NOW()pembaruan secara otomatis

masukkan deskripsi gambar di sini

Thaina
sumber
1
NOW()adalah fungsi bawaan, bukan fungsi khusus.
Rubén
@ Rubén Intinya adalah Anda dapat menyertakan fungsi NOW () dalam fungsi kustom mana pun yang ingin Anda perbarui
Thaina
13
Saat ini, argumen fungsi kustom harus deterministik, dengan kata lain, argumen tersebut tidak menggunakan NOW () sebagai argumen. Lihat developers.google.com/apps-script/guides/sheets/functions
Rubén
3
Ini melontarkan kesalahan jika Anda mencoba menggunakan NOW () di dalam fungsi khusus
Stefano Giacone
6

Jika fungsi kustom Anda berada di dalam kolom tertentu, cukup urutkan spreadsheet Anda dengan kolom tersebut.

Tindakan pengurutan memaksa penyegaran data, yang memanggil fungsi kustom Anda untuk semua baris kolom itu sekaligus.

flu
sumber
1

Ini mungkin utas yang sangat lama tetapi mungkin berguna bagi seseorang yang mencoba melakukan ini, seperti yang saya lakukan sekarang.

Bekerja dari skrip Lexi apa adanya, sepertinya tidak berfungsi lagi dengan Sheets saat ini, tetapi jika saya menambahkan variabel dummy ke dalam fungsi saya sebagai parameter (tidak perlu benar-benar menggunakannya di dalam fungsi), itu memang akan paksa lembar google untuk menyegarkan halaman lagi.

Jadi, deklarasi seperti: function myFunction (firstParam, dummy) dan kemudian memanggilnya akan seperti yang telah disarankan. Itu berhasil untuk saya.

Selain itu, jika variabel acak muncul di semua sheet yang Anda edit, cara mudah untuk membatasi ke satu sheet adalah sebagai berikut:

function onEdit(e)
{
  e.source.getSheetByName('THESHEETNAME').getRange('J1').setValue(Math.random());
}
AvengingAB
sumber
1
@ Rubén sangat mirip tetapi dengan gangguan yang bagus; alih-alih menggunakan lembar aktif, ia menggunakan nama lembar yang ditentukan, meningkatkan riwayat Anda
Jonas D.
1

Logika Skrip:

  • Fungsi Kustom tidak diperbarui kecuali argumennya berubah.
  • Buat pemicu onChange untuk mengubah semua argumen dari semua fungsi kustom di spreadsheet menggunakan textFinder

Potongan:

/*@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) + ')'
    );
}

Untuk membaca:

TheMaster
sumber
1

Seperti disebutkan sebelumnya:

Fungsi Kustom tidak diperbarui kecuali argumennya berubah.

Solusi yang mungkin adalah membuat kotak centang dalam satu sel dan menggunakan sel ini sebagai argumen untuk fungsi kustom:

  1. Buat kotak centang: pilih sel gratis misalnya [A1], pergi ke [Sisipkan]> [Kotak centang]
  2. Jadikan sel ini sebagai argumen: =myFunction(A1)
  3. Klik kotak centang untuk menyegarkan rumus
Max Makhrov
sumber
-3

Jika Anda telah menulis fungsi kustom dan menggunakannya di spreadsheet Anda sebagai rumus, maka setiap kali Anda membuka spreadsheet atau sel referensi apa pun yang diubah, rumus tersebut dihitung ulang.

Jika Anda ingin terus menatap spreadsheet dan ingin nilainya berubah, pertimbangkan untuk menambahkan pemicu berjangka waktu yang akan memperbarui sel. Baca lebih lanjut tentang pemicu di sini

Srik
sumber
10
Itu akan bagus, kecuali itu tidak berhasil ... Memuat ulang halaman tidak menyegarkan nilai. Selain itu, menghapus sel dan memasukkan kembali panggilan fungsi yang sama, tetap mempertahankan nilai lama. Jika saya memanggil fungsi yang sama persis dari sel lain, itu akan menunjukkan nilai baru, tetapi tidak di sel lama.
tbkn23