Aktualisieren Sie Daten, die von einer benutzerdefinierten Funktion in Google Sheet abgerufen wurden


89

Ich habe ein benutzerdefiniertes Google Apps-Skript geschrieben, das idInformationen von einem Webdienst empfängt und abruft (ein Preis).

Ich verwende dieses Skript in einer Tabelle und es funktioniert einwandfrei. Mein Problem ist, dass sich diese Preise ändern und meine Tabelle nicht aktualisiert wird.

Wie kann ich erzwingen, dass das Skript erneut ausgeführt und die Zellen aktualisiert werden (ohne jede Zelle manuell zu durchlaufen)?


1
Ja, hier ist eine Erklärung, die ich dazu gemacht habe: stackoverflow.com/questions/9022984/…
Henrique G. Abreu

Ich habe Ihre Erklärung im Rahmen meiner Recherche gelesen. Sehr hilfreich, danke. Ich habe den Link zu meiner Antwort hinzugefügt.
TBB23

Für diejenigen, die auf ein ähnliches (definiertes und logisches, aber manchmal unglückliches) Verhalten stoßen, kann es hilfreich sein, diese Funktionsanforderung in Google Issue Tracker zu verbessern : issuetracker.google.com/issues/36763858 .
Timothy Johns

Hier ist eine einfache Antwort, die ich gegeben habe.
Aerials

Antworten:


90

Ok, es scheint, als ob mein Problem darin bestand, dass sich Google auf seltsame Weise verhält - es führt das Skript nicht erneut aus, solange die Skriptparameter ähnlich sind, sondern verwendet zwischengespeicherte Ergebnisse aus den vorherigen Läufen. Daher wird keine erneute Verbindung zur API hergestellt und der Preis nicht erneut abgerufen. Es wird lediglich das zuvor zwischengespeicherte Skriptergebnis zurückgegeben.

Weitere Informationen finden Sie hier: https://code.google.com/p/google-apps-script-issues/issues/detail?id=888

und hier: Skript zum Zusammenfassen von Daten, die nicht aktualisiert werden

Meine Lösung bestand darin, meinem Skript einen weiteren Parameter hinzuzufügen, den ich nicht einmal verwende. Wenn Sie nun die Funktion mit einem Parameter aufrufen, der sich von früheren Aufrufen unterscheidet, muss das Skript erneut ausgeführt werden, da sich das Ergebnis für diese Parameter nicht im Cache befindet.

Wenn ich also die Funktion aufrufe, übergebe ich für den zusätzlichen Parameter "$ A $ 1". Ich habe auch einen Menüpunkt namens "Aktualisieren" erstellt. Wenn ich ihn ausführe, werden Datum und Uhrzeit in A1 eingetragen. Daher müssen alle Aufrufe des Skripts mit $ A $ 1 als zweitem Parameter neu berechnet werden. Hier ist ein Code aus meinem Skript:

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

Und wenn ich den Preis eines Artikels mit der ID 5 in eine Zelle eingeben möchte, verwende ich die folgende Formel:

=getPrice(5, $A$1)

Wenn ich die Preise aktualisieren möchte, klicke ich einfach auf den Menüpunkt "Aktualisieren" -> "Aktualisieren". Denken Sie daran, dass Sie die Tabelle nach dem Ändern des onOpen()Skripts neu laden müssen .


3
Warum nicht now () als zusätzlichen Parameter verwenden?
Fortgeschrittene

5
Sie sehen, genau wie meine Funktion nicht neu bewertet wird, weil sich ihre Parameter nicht geändert haben (dh die Werte der Zellen), wird now () auch nicht neu bewertet, da sie keine Parameter hat, daher wird ihr Rückgabewert nicht ändern und so werden sich die Parameter meiner Funktion nicht ändern. Außerdem würde die Verwendung von now () dazu führen, dass meine Funktion die ganze Zeit neu bewertet wird, was etwas schwer ist, wenn man bedenkt, dass mehrere HTTP-Aufrufe generiert werden ...
tbkn23

2
Guter Fund. Ich hatte dieses Problem, als ich benannte Bereiche als Eingabe verwendete. Anhand Ihrer Antwort habe ich herausgefunden, dass es oft gut genug ist, eine Dummy-Summe über den Bereich der Eingaben zu übergeben, wie in "Summe (B: D)", wobei die Zeilen BD in dem Bereich liegen, der von der benutzerdefinierten Funktion nachgeschlagen wird. Durch Ändern einer Zelle wird die zu ändernde Summe und die zu aktualisierende benutzerdefinierte Funktion ausgelöst. Übrigens muss die benutzerdefinierte Funktion nicht einmal den ignorierten Parameter deklarieren.
Shawn Hoover

1
Schade, dass dies immer noch die beste Lösung für dieses Problem ist. Anstatt Google nur zu erlauben, den Cache für bestimmte Funktionsaufrufe zu deaktivieren, erhöhen wir willkürlich, was im Cache gespeichert wird, um sicherzustellen, dass wir keinen zwischengespeicherten Wert erhalten ... Trotzdem, danke für den Beitrag,
GrayedFox

Versuchen Sie, einen Parameter für die benutzerdefinierte Funktion wie in diesem Beispiel
Aerials

33

Ich weiß, das ist eine alte Frage. Diese Methode erfordert jedoch keine Benutzeraktion, außer eine Änderung vorzunehmen.

Was ich getan habe, war ähnlich wie bei tbkn23.

Die Funktion, die ich neu auswerten möchte, hat einen zusätzlichen nicht verwendeten Parameter, $ A $ 1. Der Funktionsaufruf ist also

=myFunction(firstParam, $A$1)

Aber im Code ist die Funktionssignatur

function myFunction(firstParam)

Anstatt eine Aktualisierungsfunktion zu haben, habe ich die onEdit (e) -Funktion wie folgt verwendet

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

Diese Funktion wird immer dann ausgelöst, wenn eine Zelle in der Tabelle bearbeitet wird. Wenn Sie nun eine Zelle bearbeiten, wird eine Zufallszahl in A1 eingefügt. Dadurch wird die Parameterliste wie von tbkn23 vorgeschlagen aktualisiert, wodurch die benutzerdefinierte Funktion neu ausgewertet wird.


5
Funktioniert super. Nachteil ist, dass das Rückgängigmachen (Strg + Z) des Verlaufs durcheinander gebracht wird.
Jon

1
Schöner Trick mit einem nervigen Nachteil, wie Jon betonte ... Ich hoffe, jemand wird ihn verbessern :-)
Enissay

Kleine und pedantische Einschränkung mit dieser Antwort; In dem unglaublich unwahrscheinlichen Fall, dass Math.random dieselbe Nummer zurückgibt, wird es bei dieser Gelegenheit nicht aktualisiert, da diese bestimmte Nummer bereits zwischengespeichert wurde.
Woody Payne

12

Dies ist sehr spät und ich weiß nicht, ob es nützlich wäre, aber tatsächlich gibt es hier Einstellungen, die Sie NOW()automatisch aktualisieren können

Geben Sie hier die Bildbeschreibung ein


1
NOW()ist eine integrierte Funktion, keine benutzerdefinierte Funktion.
Rubén

@ Rubén Der Punkt ist, dass Sie die Funktion NOW () in jede benutzerdefinierte Funktion aufnehmen können, die aktualisiert werden soll
Thaina

13
Zu diesem Zeitpunkt sollten Argumente für benutzerdefinierte Funktionen deterministisch sein, dh sie weisen NOW () nicht als Argument zu. Siehe developer.google.com/apps-script/guides/sheets/functions
Rubén

3
Es wird ein Fehler
ausgegeben,

6

Wenn sich Ihre benutzerdefinierte Funktion in einer bestimmten Spalte befindet, ordnen Sie Ihre Tabelle einfach nach dieser Spalte.

Die Ordnungsaktion erzwingt eine Aktualisierung der Daten, wodurch Ihre benutzerdefinierte Funktion für alle Zeilen dieser Spalte gleichzeitig aufgerufen wird.


1

Dies mag ein super alter Thread sein, kann aber für jemanden nützlich sein, der dies versucht, wie ich es gerade war.

Wenn man Lexis Skript so wie es ist ausarbeitet, scheint es mit den aktuellen Sheets nicht mehr zu funktionieren, aber wenn ich die Dummy-Variable als Parameter in meine Funktion einfüge (keine Notwendigkeit, sie tatsächlich innerhalb der Funktion zu verwenden), wird dies tatsächlich der Fall sein Erzwingen Sie, dass Google Sheets die Seite erneut aktualisiert.

Also, Deklaration wie: Funktion myFunction (firstParam, Dummy) und dann Aufruf wäre wie vorgeschlagen. Das hat bei mir funktioniert.

Wenn es störend ist, dass eine Zufallsvariable auf allen von Ihnen bearbeiteten Blättern angezeigt wird, können Sie auf einfache Weise auf ein Blatt beschränken:

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

1
@ Rubén es ist sehr ähnlich, aber mit einem guten Ärgernis; Anstatt das aktive Blatt zu verwenden, wird ein definierter Blattname verwendet, wodurch Ihr Verlauf verbessert wird
Jonas D.

0

Skriptlogik:

  • Benutzerdefinierte Funktionen werden nur aktualisiert, wenn sich die Argumente ändern.
  • Erstellen Sie mit textFinder einen onChange-Trigger, um alle Argumente aller benutzerdefinierten Funktionen in der Tabelle zu ändern

Snippet:

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

Lesen:


-3

Wenn Sie eine benutzerdefinierte Funktion geschrieben und in Ihrer Tabelle als Formel verwendet haben, wird die Formel jedes Mal neu berechnet, wenn Sie die Tabelle öffnen oder eine referenzierende Zelle ändern.

Wenn Sie einfach weiter auf die Tabelle starren und möchten, dass sich ihre Werte ändern, sollten Sie einen zeitgesteuerten Trigger hinzufügen, der die Zellen aktualisiert. Lesen Sie mehr über Trigger hier


10
Das wäre einfach toll, außer es funktioniert nicht ... Beim erneuten Laden der Seite werden die Werte nicht aktualisiert. Wenn Sie die Zelle löschen und denselben Funktionsaufruf erneut eingeben, bleibt der alte Wert erhalten. Wenn ich dieselbe Funktion genau aus einer anderen Zelle aufrufe, wird der neue Wert angezeigt, jedoch nicht in der alten Zelle.
tbkn23
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.