Задать вопрос
  • Как обратиться к параметру в квадратных скобках POST запроса?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Обратите внимание, что передается x-www-form-urlencoded. При получении аргумента формы вы должны "преобразовать" его к требуемому формату. В вашем случае

    const payments = JSON.parse(e.parameter.payments);

    Следующий код возвращает первый элемент массива

    /**
     *
     * @param {GoogleAppsScript.Events.DoPost} e
     */
    function doPost(e) {
      const payments = JSON.parse(e.parameter.payments);
      return ContentService.createTextOutput(JSON.stringify(payments.products[0]));
    }


    5eb3a269ca4ea797180580.png

    Если строка запроса более интересная, то лучше всего использовать сборку для gas из https://github.com/sindresorhus/query-string.

    Более простое представление можно взять тут form2json.js

    Соответственно, чтобы получить в doPost объект нужно сделать
    form2Json(e.postData.contents)

    Пример моего приложения
    /* global form2Json */
    /* exported doPost */
    /**
     *
     * @param {GoogleAppsScript.Events.DoPost} e
     */
    function doPost(e) {
      // const payments = JSON.parse(e.parameter.payments);
      return ContentService.createTextOutput(
        JSON.stringify(form2Json(e.postData.contents), null, '  ')
      );
    }


    5eb51b8925e51758421765.png

    Обратите внимание, что возвращается не массив, а объект с индексами. Но это не мешает работать

    const data = form2Json(contents);
    console.log(JSON.stringify(data.payment.products[0]));
    Ответ написан
    3 комментария
  • Как сделать так, чтобы результат в ячейке отображался только при наличии необходимых данных в другой?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Для проверки данных можно использовать формулу IF https://support.google.com/docs/answer/3093364?hl=ru

    Например, если в A1 что-то есть, то нужно B1 умножить на C1, наче вывести пустую строку

    =IF(A1<>"";B1*C1;"")

    Для длинных формул "лучше" использовать проверку от обратного - сначала пустая строка, потом расчет

    =IF(A1="";"";B1*C1) это обычная практика для большей читаемости.
    Ответ написан
    Комментировать
  • Как быстрее всего получить данные из сторонних таблиц?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    К сожалению нельзя дать однозначный ответ на этот вопрос. Я бы разделил по способам применения.

    Например, используя формулы мы не получаем набор данных, мы видим лишь их представление. Т.н. представление по ссылке. Мы не можем менять эти данные. Накладывает большие ограничения.

    Программное получение данных является хорошей альтернативой. Но недешевой в плане эксплуатации и поддержки.

    Использование стороннего сервиса. Из адекватных предпочитаю sheetgo.

    Использование Google Apps Script. Там возможны варианты: SpreadsheetApp или Sheet Advanced Service. Для больших данных второй предпочтительнее, но не такой удобный как первый.

    Использование Google Sheets API. Очень напоминает Sheet Advanced Service, но требует своей исполнительной среды и прочих накладных расходов.

    У всех этих способов есть один большой недостаток - это все не мгновенно, потому что это сетевые приложения. К тому же требуется либо ждать события системы либо самому какие-то кнопки жмякать. Куча проблем, одним словом.

    Но без худа не бывает чуда. Попробуйте какой-нибудь более-менее пригодный пример для Sheet Advanced Service или подобрать сниппет тут google-apps-script-snippets

    С уважением.
    Ответ написан
    Комментировать
  • Как убрать незадействованные строки и столбцы?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Мне больше всего нравится дополнение Crop Sheet.
    Ответ написан
    1 комментарий
  • Как сделать, чтобы результат формулы умещался в одну ячейку?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Без примера сложно что-то сказать определенное.

    Скорее всего

    =JOIN(CHAR(10);IMPORTXML("https://yandex.ru/search/?text=test";"//h2/text()"))


    Если заголовки умещаются в одну строку, то запрос xPath можно сделать и без /text()

    Для вашего случая

    5ead238c24c74063282484.png

    =JOIN(CHAR(10);importxml(A2;"//h2"))
    Ответ написан
    2 комментария
  • Как в функции закрыть и открыть доступ на редактирования в листе ОДНОЙ ячейки?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Этого нельзя сделать. Ну, или можно, но совсем ерунда получится.

    Для перехвата "даблклика" вы должны блокировать повторное исполнение кода до момента исполнения текущего. Я обычно для этого использую LockService.

    Скрипты - это REST. REST - это пошаговое изменение состояния. Никаких "кликов" "setTimeout" и пр. в Таблицах нет. А еще там нет доступа к интерфейсу, лишь небольшие вкрапления фреймов на GAS в разрешенные области приложения (алерт, диалог, сайдбар, меню, тост).
    Ответ написан
    Комментировать
  • Вопрос о правах доступа, или как защищаются google табличные скрипты?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Скрипты никак не связаны с ограничением на ввод в ячейку, потому что скрипты это REST.
    • Если вы удалите скрипт, то защита ячеек никак не изменится.
    • Если вы попробуете изменить скрипт так, чтобы значение защищенных (условно от вас) ячеек изменилось, то сработает защита.
    • Если вы измените скрипт пользовательской функции так, чтобы она возвращала другое значение, то в защищенной ячейке она будет возвращать другое значение, но само значение ячейки по прежнему не изменить.


    По моему мнению (а ровно и по мнению Гугл) никаких логических противоречий.

    Ни в каких ячейках никаких скриптов не находится. Google Apps Script - это синтаксический сахар для Google REST API.

    К сожалению, вопрос поставлен так, что тут нельзя дать и хороший и правильный ответ. Если коротко, то вам нужно изменить свое отношение к этой парадигме. Это просто работает не так, как вы себе представляете. Для познающего это нормально.

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

    Особенно отмечу бессмысленность сравнения VBA и GAS.
    Ответ написан
  • Скрипты в Google Sheets, как начать с нуля?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Ответ написан
    Комментировать
  • Почему условное форматирование не всегда срабатывает?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Потому что у вас в одной ячейке строка, а в другой число.
    • Либо приведите все значения к одному типу
    • Либо приводите значения к одному типу при условном форматировании


    Приведение U2 к числу:

    5ea8f99bbc5c7357875514.png

    =VALUE(LEFT(S1;2))
    Ответ написан
    1 комментарий
  • Почему программа не срабатывает так, как ожидается при изменении всего одной типовой команды?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Перед тем, как копировать формулы в значения вам нужно завершить все расчеты в Таблице.

    Вызовите flush()

    SpreadsheetApp.flush();

    Например,

    /**
     *
     * @param {GoogleAppsScript.Events.SheetsOnEdit} e
     */
    function onEdit(e) {
      var activeSheet = e.source.getActiveSheet();
      SpreadsheetApp.getActive().toast(['Лист'].indexOf(activeSheet.getName()));
      if (['Лист'].indexOf(activeSheet.getName()) == -1) return;
      var r = SpreadsheetApp.getActiveRange();
      var cols = r.getColumn();
      if (cols == 6) {
        // если изменяем 6 колонку, то тригер работает и:
        var cell1 = activeSheet.getRange(2, 2); // во второй колонке берет данные из второй строки (там лежит формула)
        var destination1 = activeSheet.getRange(activeSheet.getLastRow(), 2); // находит последнюю строку с данными и выбирает вторую колонку
    
        cell1.copyTo(destination1); // копирует из второй строчки в последнюю
        var cell2 = activeSheet.getRange(2, 3); // тоже самое но только для 3 колонки
        var destination2 = activeSheet.getRange(activeSheet.getLastRow(), 3); // тоже самое но только для 3 колонки
        cell2.copyTo(destination2); // тоже самое но только для 3 колонки
        var cell3 = activeSheet.getRange(2, 5); // тоже самое но только для 5 колонки
        var destination3 = activeSheet.getRange(activeSheet.getLastRow(), 5); // тоже самое но только для 5 колонки
        cell3.copyTo(destination3); // тоже самое но только для 5 колонки
        var cell4 = activeSheet.getRange(2, 8); // тоже самое но только для 8 колонки
        var destination4 = activeSheet.getRange(activeSheet.getLastRow(), 8); // тоже самое но только для 8 колонки
        cell4.copyTo(destination4); // тоже самое но только для 8 колонки
    
        SpreadsheetApp.flush();
    
        destination1.copyTo(
          destination1,
          SpreadsheetApp.CopyPasteType.PASTE_VALUES,
          false
        ); // во второй колонке меняет формулу на значение
        destination2.copyTo(
          destination2,
          SpreadsheetApp.CopyPasteType.PASTE_VALUES,
          false
        ); // в третьей колонке меняет формулу на значение
        destination3.copyTo(
          destination3,
          SpreadsheetApp.CopyPasteType.PASTE_VALUES,
          false
        ); // в пятой колонке меняет формулу на значение
        destination4.copyTo(
          destination4,
          SpreadsheetApp.CopyPasteType.PASTE_VALUES,
          false
        ); // в восьмой колонке меняет формулу на значение
        SpreadsheetApp.getActive().toast('Готово');
      }
    }
    Ответ написан
    4 комментария
  • Чем его можно заменить или сконфигурировать стандартный триггер события "при редактировании"?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Проверяет, является ли изменяемая ячейка ячейкой 'Лист 1'!B3:

    /**
     *
     * @param {GoogleAppsScript.Events.SheetsOnEdit} e
     */
    function onEdit(e) {
      if (!/^Лист 1$/.test(e.range.getSheet().getName())) return;
      if (!/^B3$/.test(e.range.getA1Notation())) return;
      SpreadsheetApp.getActive().toast('Работаем дальше');
    }
    Ответ написан
    Комментировать
  • Иерархия файлов в проекте?

    oshliaer
    @oshliaer Куратор тега Google Apps Script
    Google Products Expert
    Это зависит от версии среды исполнения V8, STABLE, DEPRECATED_ES5.

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

    В STABLE, DEPRECATED_ES5 порядок обычно зависит от алфавитного расположения файлов, но это негарантировано.

    Что происходит у вас.

    В одном проекте есть два файла код.gs и код2.gs. В обоих есть функция onOpen. При загрузке текста программы в исполнительную среду одна функция перезапишет другую и исполняться на самом деле будет только одна функция, т.к. другой нет и в помине (она перезаписана). Какая функция будет перезаписана, это зависит от среды (см. выше).

    Что делать.

    Одним из решений может быть создание одной функции onOpen и вызова из нее двух других

    function onOpen(e){
      onOpen1(e);
      onOpen2(e);
    }
    
    function onOpen1(e){
      ...
    }
    
    function onOpen2(e){
      ...
    }


    Или же вы можете создать еще один проект в том же контейнере [Таблице] (см. меню текущего проекта).
    Ответ написан
    Комментировать
  • Как сделать универсальную формулу подсчета возраста?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Какая-то куча вопросов. Наверное, стоит обратить внимание на какую-то конкретную проблему.

    5ea6dd9fa3c2a573383387.png

    Это не "глючит". Это свойство вычислительных систем. Можете взять на вооружение: каждый день в Таблицах гугл - это целое число от даты "31.12.1899". Отрицательное число - это года в сторону прошлого.

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

    Например,

    =TEXT(TODAY();"YYYY")-TEXT(A7;"YYYY")

    Для дней и месяцев, при таком подходе, могут появляться лидирующие нули. "обрезать" их лучше всего через VALUE

    =VALUE(TEXT(TODAY();"YYYY"))-VALUE(TEXT(A7;"DD"))
    Ответ написан
    4 комментария
  • Как решить долгую загрузку данных не удаляя их?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Скорее всего нет. Тут либо делать 1000 запросов программой, либо ждать.
    Ответ написан
    Комментировать
  • Можно сделать изображение как на сайте?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Технически, как-то это можно повторить, но потребуются внешние программы и либо расширения браузера либо еще какие-то примочки со скриптами.

    Возможно, вам стоит рассмотреть представление Таблицы в другом приложении. Например, https://awesome-table.com
    Ответ написан
    Комментировать
  • Как поставить проверку на ячейку, чтобы там писалось только 8 цифр?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Можно использовать проверку данных. Меню -Данные - Проверка данных

    5ea56ad2ace34728499297.png

    Например, для ячейки '8 ЦИФР'!D9

    можно использовать формулу

    =REGEXMATCH(B9;"^\d{8}$")

    5ea56ae43c367109463122.png
    Ответ написан
    Комментировать
  • Статистика по категориям. Можно ли сортировать ответы Google Forms по параметру/ключу?

    oshliaer
    @oshliaer
    Google Products Expert
    Статистика Формы тут не поможет. Вам нужно привязать данные Формы к Таблице и строить свою статистику.

    https://support.google.com/docs/answer/2917686?hl=ru
    Ответ написан
    Комментировать
  • Есть ли горячие клавиши для действий в подсказке неправильного слова?

    oshliaer
    @oshliaer
    Google Products Expert
    Насколько я знаю, есть только проверка всего текста через [CTRL]+[ALT]+[X]. Не очень интуитивно, но по табам переходит нормально. Ignore можно сделать за 2 клика.

    Другой вариант, использовать стандартное сочетание [SHIFT]+[F10] для вызова контекстного меню [ПКМ].
    Ответ написан
    Комментировать
  • Как посчитать в наборе цифр количество нулей?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Для подсчета количества цифр вы можете использовать LEN и регулярные выражения.

    =LEN(REGEXREPLACE(TO_TEXT(A10);"[^1-9]";""))

    Для вывода нулей, тоже самое

    =LEN(REGEXREPLACE(TO_TEXT(A10);"[^0]";""))

    Чтобы количеств нулей написать цифрой прописью, вам понадобится расширение NUMBERTEXT

    =NUMBERTEXT("cardinal-feminine "& LEN(REGEXREPLACE(TO_TEXT(A10);"[^0]";"")))


    5ea0f930c768d543174740.png
    Ответ написан
    7 комментариев
  • Почему код определяет другое число?

    oshliaer
    @oshliaer Куратор тега Google Sheets
    Google Products Expert
    Нужно немного усилить регулярное выражение - заменить на ".*?\d+\s*\-.*?(\d+)".

    =REGEXEXTRACT(INDEX(IMPORTHTML(N14;"table";0);2;1);".*?\d+\s*\-.*?(\d+)")
    Ответ написан