Actualiser les données récupérées par une fonction personnalisée dans Google Sheet

92

J'ai écrit un script Google Apps personnalisé qui recevra idet récupérera des informations d'un service Web (un prix).

J'utilise ce script dans une feuille de calcul et cela fonctionne très bien. Mon problème est que ces prix changent et que ma feuille de calcul n'est pas mise à jour.

Comment puis-je le forcer à réexécuter le script et à mettre à jour les cellules (sans passer manuellement sur chaque cellule)?

tbkn23
la source
1
Oui, voici une explication que j'ai faite à ce sujet: stackoverflow.com/questions/9022984/…
Henrique G. Abreu
J'ai lu votre explication dans le cadre de mes recherches. Très utile, merci. J'ai ajouté le lien vers ma réponse.
tbkn23
Pour ceux qui rencontrent un comportement similaire (défini et logique, mais parfois malheureux), il peut être utile de voter pour cette demande de fonctionnalité dans Google Issue Tracker: issuetracker.google.com/issues/36763858 .
Timothy Johns
Voici une réponse simple que j'ai faite.
Antennes le
De vraies solutions de contournement: stackoverflow.com/a/56802017 et stackoverflow.com/a/61946592
TheMaster

Réponses:

92

Ok, il semble que mon problème était que Google se comporte d'une manière étrange - il ne réexécute pas le script tant que les paramètres du script sont similaires, il utilise les résultats mis en cache des exécutions précédentes. Par conséquent, il ne se reconnecte pas à l'API et ne récupère pas le prix, il renvoie simplement le résultat du script précédent qui a été mis en cache.

Pour plus d'informations, cliquez ici: https://code.google.com/p/google-apps-script-issues/issues/detail?id=888

et ici: Script pour résumer les données non actualisées

Ma solution était d'ajouter un autre paramètre à mon script, que je n'utilise même pas. Désormais, lorsque vous appelez la fonction avec un paramètre différent des appels précédents, elle devra réexécuter le script car le résultat de ces paramètres ne sera pas dans le cache.

Donc, chaque fois que j'appelle la fonction, pour le paramètre supplémentaire je passe "$ A $ 1". J'ai également créé un élément de menu appelé refresh, et lorsque je l'exécute, il met la date et l'heure actuelles dans A1, par conséquent tous les appels au script avec $ A $ 1 comme deuxième paramètre devront recalculer. Voici du code de mon script:

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

Et quand je veux mettre le prix de l'article avec l'ID 5 dans une cellule, j'utilise la formule suivante:

=getPrice(5, $A$1)

Lorsque je souhaite actualiser les prix, je clique simplement sur l'élément de menu "Actualiser" -> "Actualiser". N'oubliez pas que vous devez recharger la feuille de calcul après avoir modifié le onOpen()script.

tbkn23
la source
4
pourquoi ne pas utiliser now () comme paramètre supplémentaire?
Avancé
5
Vous voyez, tout comme ma fonction ne sera pas réévaluée car ses paramètres n'ont pas changé (c'est-à-dire les valeurs des cellules), now () ne sera pas réévalué non plus car il n'a pas de paramètres, donc sa valeur de retour sera ne change pas et donc les paramètres de ma fonction ne changeront pas. De plus, l'utilisation de now () entraînerait une réévaluation permanente de ma fonction, ce qui est un peu lourd étant donné qu'elle génère plusieurs appels HTTP ...
tbkn23
2
Bonne trouvaille. J'ai eu ce problème en utilisant des plages nommées comme entrée. En utilisant votre réponse, j'ai compris qu'il était souvent assez bon de passer une somme fictive sur la plage d'entrées, comme dans "somme (B: D)", où les lignes BD sont dans la plage recherchée par la fonction personnalisée. La modification d'une cellule déclenchera la modification de la somme et l'actualisation de la fonction personnalisée. À propos, il semble que la fonction personnalisée n'ait même pas à déclarer le paramètre ignoré.
Shawn Hoover
1
Dommage que ce soit toujours la meilleure solution que j'ai trouvée à ce problème. Plutôt que Google nous autorise simplement à désactiver le cache pour des appels de fonction particuliers, nous augmentons arbitrairement ce qui est stocké dans le cache juste pour nous assurer de ne pas obtenir une valeur mise en cache ... Pourtant, merci pour le message,
GrayedFox
Essayez d'utiliser un paramètre pour votre fonction personnalisée comme cet exemple
Antennes le
33

Je sais que c'est un peu une vieille question. Mais cette méthode ne nécessite aucune action de l'utilisateur, sauf une modification.

Ce que j'ai fait était similaire à tbkn23.

La fonction que je veux réévaluer a un paramètre supplémentaire inutilisé, $ A $ 1. Donc, l'appel de fonction est

=myFunction(firstParam, $A$1)

Mais dans le code, la signature de la fonction est

function myFunction(firstParam)

Au lieu d'avoir une fonction Refresh, j'ai utilisé la fonction onEdit (e) comme ceci

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

Cette fonction est déclenchée chaque fois qu'une cellule de la feuille de calcul est modifiée. Alors maintenant que vous éditez une cellule, un nombre aléatoire est placé dans A1, cela actualise la liste des paramètres comme suggéré par tbkn23, provoquant la réévaluation de la fonction personnalisée.

Brosse Lexi
la source
5
Fonctionne très bien. L'inconvénient est que l'historique d'annulation (ctrl + z) est foiré.
Jon
1
Belle astuce avec un inconvénient ennuyeux comme l'a souligné Jon ... J'espère que quelqu'un l'améliorera :-)
Enissay
Petite mise en garde pédante avec cette réponse; dans l'événement incroyablement improbable, Math.random renvoie le même nombre, à cette occasion, il ne sera pas mis à jour, car ce numéro particulier a déjà été mis en cache.
Woody Payne
12

C'est très tard et je ne sais pas que ce serait utile mais en fait il y a des paramètres ici, vous pouvez faire la NOW()mise à jour automatiquement

entrez la description de l'image ici

Thaina
la source
1
NOW()est une fonction intégrée, pas une fonction personnalisée.
Rubén
@ Rubén Le fait est que vous pouvez inclure la fonction NOW () dans n'importe quelle fonction personnalisée que vous souhaitez mettre à jour
Thaina
13
À ce stade, les arguments des fonctions personnalisées doivent être déterministes, en d'autres termes, ils n'autorisent pas NOW () comme argument. Voir developer.google.com/apps-script/guides/sheets/functions
Rubén
3
Il génère une erreur si vous essayez d'utiliser NOW () dans une fonction personnalisée
Stefano Giacone
6

Si votre fonction personnalisée se trouve dans une colonne spécifique, commandez simplement votre feuille de calcul par cette colonne.

L'action de classement force une actualisation des données, qui appelle votre fonction personnalisée pour toutes les lignes de cette colonne à la fois.

grippe
la source
1

Cela peut être un fil de discussion très ancien mais peut être utile pour quelqu'un qui essaie de le faire, comme je l'étais tout à l'heure.

Fonctionnant à partir du script de Lexi tel quel, cela ne semblait plus fonctionner avec les feuilles actuelles, mais si j'ajoute la variable factice dans ma fonction en tant que paramètre (pas besoin de l'utiliser réellement dans la fonction), cela fonctionnera en effet forcer les feuilles de google à actualiser à nouveau la page.

Donc, une déclaration comme: function myFunction (firstParam, dummy) et l'appeler ensuite serait comme cela a été suggéré. Cela a fonctionné pour moi.

De plus, s'il est gênant pour une variable aléatoire d'apparaître sur toutes vos feuilles que vous éditez, un remède facile pour limiter à une feuille est le suivant:

function onEdit(e)
{
  e.source.getSheetByName('THESHEETNAME').getRange('J1').setValue(Math.random());
}
AvengingAB
la source
1
@ Rubén c'est très similaire mais avec une bonne nuisance; au lieu d'utiliser la feuille active, il utilise un nom de feuille défini, améliorant votre historique
Jonas D.
1

Logique de script:

  • Les fonctions personnalisées ne sont pas mises à jour à moins que ses arguments ne changent.
  • Créez un déclencheur onChange pour modifier tous les arguments de toutes les fonctions personnalisées dans la feuille de calcul à l'aide de textFinder

Fragment:

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

Lire:

Le maître
la source
1

Comme mentionné plus tôt:

Les fonctions personnalisées ne sont pas mises à jour à moins que ses arguments ne changent.

La solution possible est de créer une case à cocher dans une seule cellule et d'utiliser cette cellule comme argument pour la fonction personnalisée:

  1. Créez une case à cocher: sélectionnez la cellule libre, par exemple [A1], allez dans [Insérer]> [Case à cocher]
  2. Faites de cette cellule un argument: =myFunction(A1)
  3. Cliquez sur la case à cocher pour actualiser la formule
Max Makhrov
la source
-3

Si vous avez écrit une fonction personnalisée et que vous l'avez utilisée dans votre feuille de calcul en tant que formule, chaque fois que vous ouvrez la feuille de calcul ou qu'une cellule de référence est modifiée, la formule est recalculée.

Si vous souhaitez simplement continuer à regarder la feuille de calcul et que ses valeurs changent, envisagez d'ajouter un déclencheur chronométré qui mettra à jour les cellules. En savoir plus sur les déclencheurs ici

Srik
la source
10
Ce serait tout simplement génial, sauf que cela ne fonctionne pas ... Le rechargement de la page ne rafraîchit pas les valeurs. De plus, la suppression de la cellule et la réintroduction du même appel de fonction conserve toujours l'ancienne valeur. Si j'appelle la même fonction exactement à partir d'une autre cellule, elle affichera la nouvelle valeur, mais pas dans l'ancienne cellule.
tbkn23