Как я могу правильно вызвать функцию с помощью кнопки пользовательского интерфейса с растущим листом Google?

#google-apps-script #google-sheets #google-places-api

Вопрос:

Я начал с этого проекта в надежде, что API Google Places сможет автоматизировать поиск конкретной информации о бизнесе и местах. Хотя я начал с отдельных функций, я вижу, что это создало чрезмерное количество запросов, которые прошли через мой бесплатный ежемесячный кредит Google Cloud. Это произошло потому, что я написал функции, которые вызывались каждый раз, когда Лист открывался в любом случае.

Вместо этого я хочу, чтобы функции запускались только тогда, когда я использую кнопку пользовательского интерфейса для ее вызова. Но как я могу указать, что он должен выполняться только в тех случаях, когда информация о местах еще не заполнена на листе?

Я бы ввел название места в колонку A, а в колонках B — F у меня будет функция поиска запрошенной информации. Мой скрипт просматривает название места в столбце А и находит идентификатор Google Place. Оттуда он форматирует URL-адрес для этой записи Google Places и извлекает запрошенную информацию из объединенного URL-адреса.

введите описание изображения здесь

Вот мой текущий код:

 // This location basis is used to narrow the search -- e.g. if you were
// building a sheet of bars in NYC, you would want to set it to coordinates
// in NYC.
// You can get this from the url of a Google Maps search.
const LOC_BASIS_LAT_LON = "37.7644856,-122.4472203"; // e.g. "37.7644856,-122.4472203"

function COMBINED2(text) {
  var API_KEY = 'AxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxQ';
  var baseUrl = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json';
  var queryUrl = baseUrl   '?input='   text   'amp;inputtype=textqueryamp;key='   API_KEY   "amp;locationbias=point:"   LOC_BASIS_LAT_LON;
  var response = UrlFetchApp.fetch(queryUrl);
  var json = response.getContentText();
  var placeId = JSON.parse(json);
  var ID = placeId.candidates[0].place_id;

  var fields = 'name,formatted_address,formatted_phone_number,website,url,types,opening_hours';
  var baseUrl2 = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=';
  var queryUrl2 = baseUrl2   ID   'amp;fields='   fields   'amp;key='  API_KEY   "amp;locationbias=point:"   LOC_BASIS_LAT_LON;

  if (ID == '') {
    return 'Give me a Google Places URL...';
  }

  var response2 = UrlFetchApp.fetch(queryUrl2);
  var json2 = response2.getContentText();
  var place = JSON.parse(json2).resu<

  var placeAddress = place.formatted_address;
  var placePhoneNumber = place.formatted_phone_number;
  var placeWebsite = place.website;
  var placeURL = place.url;

  var weekdays = '';
  place.opening_hours.weekday_text.forEach((weekdayText) => {
    weekdays  = ( weekdayText   'rn' );
  } );

  var data = [ [
    place.formatted_address,
    place.formatted_phone_number,
    place.website,
    place.url,
    weekdays.trim()
  ] ];

  return data;
}


// add menu
// onOpen is a special function
// runs when your Sheet opens
function onOpen() {
  
  const ui = SpreadsheetApp.getUi();
  
  ui.createMenu("Custom Menu")
      .addItem("Get place info","COMBINED2")
      .addToUi();
  
}
 

Я получил помощь в отдельном сообщении, в котором мне посоветовали использовать другую функцию для вызова COMBINED2 , но я не уверен, применимо ли это по-прежнему при изменении моих планов.

 // this function calls COMBINED2()
function call_COMBINED2() {
  var ss = SpreadsheetApp.getActiveSheet();
  var text = ss.getRange("A2").getValue();
  var data = COMBINED2(text);
  var dest = ss.getRange("B2:F2");
  dest.setValues(data);
}
 

Если это что-то изменит, мой план на будущее будет состоять в том, чтобы иметь две кнопки в пользовательском пользовательском интерфейсе. Один из них будет работать над первоначальным поиском данных о местоположении. Второй сделает обновление. Если будет обнаружено изменение и ячейка будет изменена/обновлена, то она каким — то образом выделится, чтобы я мог это отметить.

Этот проект-часть того, как я путешествую. Я часто составляю списки рекомендуемых и проверенных достопримечательностей, баров и ресторанов в Google, чтобы я мог импортировать лист в Google myMap для справки, когда мы действительно посещаем. Со временем эти листы/карты, как правило, устаревают с изменениями (особенно с COVID). Я надеюсь, что это послужит их доказательству в будущем и облегчит их обновление.

Ответ №1:

Триггер onOpen в вашем сценарии предназначен только для добавления пользовательского меню на ваш лист. Функция будет выполнена только в том случае, если пользователь выбрал пункт в меню, связанный с этой функцией. В вашем примере щелчок Get place info приведет к выполнению COMBINED2 функции.

введите описание изображения здесь

Кроме того, выполнение сценария только в том случае, если информация о месте отсутствует на листе, невозможно, вам необходимо запустить сценарий, чтобы получить идентификатор места и сравнить его с данными на листе. В вашем примере в качестве идентификатора можно использовать place.url. Единственное, что вы можете сделать, — это запретить сценарию заполнять лист.

Здесь я обновил ваш скрипт, изменив функцию, связанную с Get place info writeToSheet() «кому». writeToSheet() позвонит COMBINED2(text) , чтобы получить информацию о месте, и с помощью текстового навигатора проверит, существует ли URL-адрес места на листе. Если результат TextFinder равен 0, он заполнит лист.

 // const LOC_BASIS_LAT_LON = "40.74516247433546, -73.98621366765811"; // e.g. "37.7644856,-122.4472203"
const LOC_BASIS_LAT_LON = "37.7644856,-122.4472203";

function COMBINED2(text) {
  var API_KEY = 'enter api key here';
  var baseUrl = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json';
  var queryUrl = baseUrl   '?input='   text   'amp;inputtype=textqueryamp;key='   API_KEY   "amp;locationbias=point:"   LOC_BASIS_LAT_LON;
  var response = UrlFetchApp.fetch(queryUrl);
  var json = response.getContentText();
  var placeId = JSON.parse(json);
  var ID = placeId.candidates[0].place_id;
  var fields = 'name,formatted_address,formatted_phone_number,website,url,types,opening_hours';
  var baseUrl2 = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=';
  var queryUrl2 = baseUrl2   ID   'amp;fields='   fields   'amp;key='  API_KEY   "amp;locationbias=point:"   LOC_BASIS_LAT_LON;

  if (ID == '') {
    return 'Give me a Google Places URL...';
  }

  var response2 = UrlFetchApp.fetch(queryUrl2);
  var json2 = response2.getContentText();
  var place = JSON.parse(json2).resu<

  var weekdays = '';
  place.opening_hours.weekday_text.forEach((weekdayText) => {
    weekdays  = ( weekdayText   'rn' );
  } );

  var data = [
    place.name,
    place.formatted_address,
    place.formatted_phone_number,
    place.website,
    place.url,
    weekdays.trim()
  ];

  return data;
}

function getColumnLastRow(range){
  var ss = SpreadsheetApp.getActiveSheet();
  var inputs = ss.getRange(range).getValues();
  return inputs.filter(String).length;
}

function writeToSheet(){
  var ss = SpreadsheetApp.getActiveSheet();
  var lastRow = getColumnLastRow("A1:A");
  var text = ss.getRange("A" lastRow).getValue();
  var data = COMBINED2(text);
  var placeCid = data[4];
  var findText = ss.createTextFinder(placeCid).findAll();
  if(findText.length == 0){
    ss.getRange(lastRow,2,1, data.length).setValues([data])
  }
}

function onOpen() {
  const ui = SpreadsheetApp.getUi();  
  ui.createMenu("Custom Menu")
      .addItem("Get place info","writeToSheet")
      .addToUi();
}
 

Выход:

Пример 1:

введите описание изображения здесь

После нажатия на пользовательское меню:

введите описание изображения здесь

Пример 2:

введите описание изображения здесь

После нажатия на пользовательское меню:

введите описание изображения здесь

Примечание: Поскольку мы используем lastRow, новая запись должна быть вставлена под последней строкой столбца A. В противном случае она перезапишет последнюю запись.

Ссылка:

Комментарии:

1. Извините, что так долго следил за вашим ответом. Я попытался реализовать это, но не смог добиться таких же результатов, как вы. Я попытался ввести одно или два названия мест в столбец A, но результаты заполнили бы, казалось бы, случайную запись под моей последней введенной строкой и не нашли бы никаких данных для мест, которые я ввел в столбец A. Связано ли это с использованием ввода ячейки ss.getRange(range).getValue() , как вы описали в своей последней строке?

2. @JeffAbrahams — Вы хотите заполнить столбцы B-G той же строкой, что и столбец A?

3. Да, таково было мое намерение. Я хотел, чтобы можно было ввести название места в колонку А и чтобы запрошенная информация отображалась в той же строке.

4. @JeffAbrahams — Смотрите мой обновленный ответ

5. Я чувствую, что мы почти на месте… Итак, я вошел в три пивоварни в районе определения местоположения GPS в Сан-Франциско. Пивоварение Lupulandia в A2, Dirty Robot Brew Работает в A3, а Cellarmaker Brewing Co. в A4. Когда я нажимаю меню пользовательских функций, он звонит getColumnLastRow , чтобы найти последний элемент вошел, а потом работает COMBINED2 но вот только собираюсь посмотреть Cellarmaker пивоварения Co. так как он является последним в колонне, когда мы хотим выглядеть на все три пока TextFinder не найти места URL-адрес, как мы указали на writeToSheet это нужно перебирать строки?