Автоматизация скрипта при изменении значения ячейки - PullRequest
1 голос
/ 02 ноября 2019

Я новичок в Google Script for Sheets.

У меня есть скрипт, который работает для геокодирования адреса. Это работает, когда я выбираю три столбца «Адрес», «Lat», «Lng» и нажимаю вкладку «Геокод». Однако, когда я его использую, мне нужно нажать на эту вкладку, а затем выбрать «запустить скрипт на выбранных ячейках», прежде чем он будет работать.

Итак, что я получу после:
Если адрес введениспользуя другое приложение, в ячейку J2 (например), я бы хотел, чтобы Google Sheets автоматически выбирал J2, K2 и L2, а затем запускал скрипт геокодирования для этих ячеек.

Надеюсь, это имеет смысл?

Извините, но мои знания сценариев минимальны, но я могу следовать четким инструкциям, если кто-нибудь сможет помочь.

Вот код:

  return PropertiesService.getDocumentProperties().getProperty('GEOCODING_REGION') || 'us';
}

/*
function setGeocodingRegion(region) {
  PropertiesService.getDocumentProperties().setProperty('GEOCODING_REGION', region);
  updateMenu();
}
function promptForGeocodingRegion() {
  var ui = SpreadsheetApp.getUi();
  var result = ui.prompt(
    'Set the Geocoding Country Code (currently: ' + getGeocodingRegion() + ')',
    'Enter the 2-letter country code (ccTLD) that you would like ' +
    'the Google geocoder to search first for results. ' +
    'For example: Use \'uk\' for the United Kingdom, \'us\' for the United States, etc. ' +
    'For more country codes, see: https://en.wikipedia.org/wiki/Country_code_top-level_domain',
    ui.ButtonSet.OK_CANCEL
  );
  // Process the user's response.
  if (result.getSelectedButton() == ui.Button.OK) {
    setGeocodingRegion(result.getResponseText());
  }
}
*/

function addressToPosition() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var cells = sheet.getActiveRange();

  // Must have selected 3 columns (Address, Lat, Lng).
  // Must have selected at least 1 row.

  if (cells.getNumColumns() != 3) {
    Logger.log("Must select at least 3 columns: Address, Lat, Lng columns.");
    return;
  }

  var addressColumn = 1;
  var addressRow;

  var latColumn = addressColumn + 1;
  var lngColumn = addressColumn + 2;

  var geocoder = Maps.newGeocoder().setRegion(getGeocodingRegion());
  var location;

  for (addressRow = 1; addressRow <= cells.getNumRows(); ++addressRow) {
    var address = cells.getCell(addressRow, addressColumn).getValue();

    // Geocode the address and plug the lat, lng pair into the 
    // 2nd and 3rd elements of the current range row.
    location = geocoder.geocode(address);

    // Only change cells if geocoder seems to have gotten a 
    // valid response.
    if (location.status == 'OK') {
      lat = location["results"][0]["geometry"]["location"]["lat"];
      lng = location["results"][0]["geometry"]["location"]["lng"];

      cells.getCell(addressRow, latColumn).setValue(lat);
      cells.getCell(addressRow, lngColumn).setValue(lng);
    }
  }
};

function positionToAddress() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var cells = sheet.getActiveRange();

  // Must have selected 3 columns (Address, Lat, Lng).
  // Must have selected at least 1 row.

  if (cells.getNumColumns() != 3) {
    Logger.log("Must select at least 3 columns: Address, Lat, Lng columns.");
    return;
  }

  var addressColumn = 1;
  var addressRow;

  var latColumn = addressColumn + 1;
  var lngColumn = addressColumn + 2;

  var geocoder = Maps.newGeocoder().setRegion(getGeocodingRegion());
  var location;

  for (addressRow = 1; addressRow <= cells.getNumRows(); ++addressRow) {
    var lat = cells.getCell(addressRow, latColumn).getValue();
    var lng = cells.getCell(addressRow, lngColumn).getValue();

    // Geocode the lat, lng pair to an address.
    location = geocoder.reverseGeocode(lat, lng);

    // Only change cells if geocoder seems to have gotten a 
    // valid response.
    Logger.log(location.status);
    if (location.status == 'OK') {
      var address = location["results"][0]["formatted_address"];

      cells.getCell(addressRow, addressColumn).setValue(address);
    }
  }  
};

function generateMenu() {
  // var setGeocodingRegionMenuItem = 'Set Geocoding Region (Currently: ' + getGeocodingRegion() + ')';

  // {
  //   name: setGeocodingRegionMenuItem,
  //   functionName: "promptForGeocodingRegion"
  // },

  var entries = [{
    name: "Geocode Selected Cells (Address to   Lat, Long)",
    functionName: "addressToPosition"
  },
  {
    name: "Geocode Selected Cells (Address from Lat, Long)",
    functionName: "positionToAddress"
  }];

  return entries;
}

function updateMenu() {
  SpreadsheetApp.getActiveSpreadsheet().updateMenu('Geocode', generateMenu())
}

/**
 * Adds a custom menu to the active spreadsheet, containing a single menu item
 * for invoking the readRows() function specified above.
 * The onOpen() function, when defined, is automatically invoked whenever the
 * spreadsheet is opened.
 *
 * For more information on using the Spreadsheet API, see
 * https://developers.google.com/apps-script/service_spreadsheet
 */
function onOpen() {
  SpreadsheetApp.getActiveSpreadsheet().addMenu('Geocode', generateMenu());
  // SpreadsheetApp.getActiveSpreadsheet().addMenu('Region',  generateRegionMenu());
  // SpreadsheetApp.getUi()
  //   .createMenu();
};

Ответы [ 2 ]

0 голосов
/ 04 ноября 2019

Я бы предложил триггер onEdit (), но поскольку вы не будете обновлять Spreasheet вручную, а программно, триггер onEdit () не будет работать для вас, потому что триггеры запускаются только в том случае, если действие выполняется вручную [1]. Я предлагаю вам использовать управляемый временем триггер, чтобы обновлять лист каждый раз [1], например:

function createTimeDrivenTriggers() {
  // Trigger every 6 hours.
  ScriptApp.newTrigger('myFunction')
      .timeBased()
      .everyHours(6)
      .create();

  // Trigger every Monday at 09:00.
  ScriptApp.newTrigger('myFunction')
      .timeBased()
      .onWeekDay(ScriptApp.WeekDay.MONDAY)
      .atHour(9)
      .create();
}

Вы можете получить все данные с помощью функции getDataRange () [2] и использоватьзначения для обновления всех строк. Другой вариант - сохранить количество строк в атрибуте с помощью службы свойств [3] и использовать его для сравнения количества новых строк и обновления только этих новых строк.

ОБНОВЛЕНИЕ

После просмотра ваших комментариев я собрал следующий код:

function getGeocodingRegion() {
  return PropertiesService.getScriptProperties().getProperty('GEOCODING_REGION') || 'us';
}

function createTimeDrivenTrigger() {
  ScriptApp.newTrigger("addressToPosition")
  .timeBased()
  .everyMinutes(15)
  .create();
}

function addressToPosition() {
  var sheet = SpreadsheetApp.openById("[SPREADSHEET-ID]").getSheets()[0];
  var cells = sheet.getRange("M2:M" + sheet.getLastRow()).getValues();

  var geocoder = Maps.newGeocoder().setRegion(getGeocodingRegion());
  var location;
  var locationsArray = [];

  for (var addressRow = 0; addressRow<cells.length; addressRow++) {
    var address = cells[addressRow][0];
    locationsArray[addressRow] = [];
    var err;
    // Geocode the address and plug the lat, lng pair into the 
    // 2nd and 3rd elements of the current range row.
    try{
      location = geocoder.geocode(address);
    }
    catch(error) {
      err = error;
      Logger.log(err);
    }

    // Only change cells if geocoder seems to have gotten a 
    // valid response.
    if (location.status == 'OK') {
      var lat = location["results"][0]["geometry"]["location"]["lat"];
      var lng = location["results"][0]["geometry"]["location"]["lng"];

      locationsArray[addressRow][0] = lat;
      locationsArray[addressRow][1] = lng;
    }
    else {
      locationsArray[addressRow][0] = err;
      locationsArray[addressRow][1] = err;
    }
  }

  //Set all latitudes and longitudes 
  sheet.getRange("N2:O" + sheet.getLastRow()).setValues(locationsArray);  
}

Вам необходимо заменить идентификатор электронной таблицы и один раз запустить функцию createTimeDrivenTrigger, которая создаст триггер для запуска функции addressToPositionкаждые 15 мин. Это позволит найти последнюю строку в первом листе, получить адреса из столбца M и поместить значения широты и долготы в столбцы N и O соответственно.

[1] https://developers.google.com/apps-script/guides/triggers/installable#restrictions

[2] https://developers.google.com/apps-script/reference/spreadsheet/sheet#getDataRange()

[3] https://developers.google.com/apps-script/reference/properties

0 голосов
/ 02 ноября 2019

Вы должны посмотреть на Триггеры скриптов приложений . В частности, кажется, что вам нужна функция onEdit().

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

Было бы также неплохо опубликовать некоторые псевдокоды или фрагменты кода, объясняющие, что вы сделали, потому что это будетПроще показать, как интегрировать решение в существующий код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...