воскресенье, 21 июня 2020 г.

Табличные диалоговые окна. Подсказки ввода dadata.ru

Таблицы google имеют достаточно большие возможности в построении различного рода CRM. Пользуясь не только формулами, но и скриптами, можно достаточно быстро выстроить модель обработки различного рода данных. 


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

function onOpen(e) {
  SpreadsheetApp.getUi() 
      .createMenu('Custom menu')
      .addItem('Создать лист', 'createNewSheet')
      .addItem('Создать лист с названием','createNewSheetWithName')
      .addToUi();
}
function createNewSheet(){
    let answer=Browser.msgBox('Вы собираетесь создать новый лист? Вы уверены?',Browser.Buttons.YES_NO);
    if (answer=='yes'){
        SpreadsheetApp.getActive().insertSheet().activate()
    }
}

Во-первых, мы добавили своё меню с одним пунктом Создать лист. Во-вторых, используя методы Browser создали дополнительную проверку для пользователя. И новый лист будет создан только если пользователь подтвердит и нажмёт Да. 
Методы Browser ограничены оповещением и набором кнопок. Было бы гораздо лучше если бы при создании нового листа мы могли бы задать его название. 

function createNewSheetWithName(){
    let answer = Browser.inputBox('Новый лист','Введите название листа' , Browser.Buttons.OK_CANCEL)
    if (answer!='cancel'){
        SpreadsheetApp.getActive().insertSheet().setName(answer).activate()
    }
}

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

1. Необходимо сформировать файл html содержащий в себе такую форму
<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <base target="_top">
  <style>
.group {
  position: relative;
  margin-bottom: 30px;
}

input {
  font-size: 16px;
  padding: 10px;
  display: block;
  width: 300px;
  border: none;
  border-bottom: 1px solid #ccc;
}
input:focus {
  outline: none;
}
label {
  color: #999;
  font-size: 18px;
  position: absolute;
  pointer-events: none;
  left: 10px;
  top: 15px;
  transition: 0.2s ease all;
  -moz-transition: 0.2s ease all;
  -webkit-transition: 0.2s ease all;
}

/* active state */
input:focus ~ label, input:valid ~ label {
  top: -10px;
  font-size: 14px;
  color: #5264AE;
}


/* BOTTOM BARS ================================= */
.bar {
  position: relative;
  display: block;
  width: 320px;
}
.bar:before, .bar:after {
  content: "";
  height: 2px;
  width: 0;
  bottom: 0;
  position: absolute;
  background: #5264AE;
  transition: 0.2s ease all;
  -moz-transition: 0.2s ease all;
  -webkit-transition: 0.2s ease all;
}
.bar:before {
  left: 50%;
}
.bar:after {
  right: 50%;
}

/* active state */
input:focus ~ .bar:before,
input:focus ~ .bar:after {
  width: 50%;
}
      </style>
  </head>
  <body>
<form onsubmit="sendData(); return false;">
    <div class="group">      
       <input type="text" id="name">
       <span class="bar"></span>
       <label>ФИО:</label>
    </div>
    <div class="group">      
       <input type="text" id="address">
       <span class="bar"></span>
       <label>Адрес:</label>
    </div>
    <div class="group">      
      <input type="text" id="organisation">
      <span class="bar"></span>
      <label>Организация:</label>
   </div>
   <input type="submit" value="Ok">
 </form>
<script>
function sendData()
{
  var outData = {};
  var elements = document.forms[0].querySelectorAll( "input" );
  for(var i=0;i<elements.length;i++) outData[elements[i].id] = elements[i].value;
  google.script.run.sendData(outData);
  google.script.host.close()
}
   
</script>
  </body>
</html>
Стилевое наполнение было взято отсюда.

2. Написать функцию - обработчик данных который был указан в html файле, а именно функцию 
sendData:
function sendData(form){
  SpreadsheetApp.getActive().getSheetByName('Клиенты').appendRow([form.name, form.address,form.organisation])} 
  }
3. Написать функцию, которая позволит отображать наш html в интерфейсе таблиц, daData:
function daData(){
    let html=HtmlService.createHtmlOutputFromFile('index')
    SpreadsheetApp.getUi().showModelessDialog(html,'Ввод данных клиента')
}
здесь index - название нашего html файла в редакторе скриптов.
 
И вот вроде бы и всё, но хочется чего то большего и красивого. Хочется подключить к форме сервис подсказок dadata.ru - замечательно описанный сервис с api и большим количеством плюшек. 

Подсмотрев описание api подсказок, можно достаточно просто и быстро реализовать такую вещь.

Где посмотреть весь код и что то изменить для себя ? - 
Сделайте копию таблицы.

Если захотите воспользоваться подсказками daData.ru необходимо пройти у них регистрацию, из личного кабинета скопировать API ключ. И заменить в редакторе скриптов в файле index2.html в 104 строке myApiToken на свой.

Если остались вопросы милости прошу в комментарии.

PS: Достаточно давно в мессенджере Телеграм существует чат и канал, в которых помогают людям работающим с google таблицами.
Любой ваш вопрос по теме не останется без ответа.
Возникают вопросы, милости просим.
 

14 комментариев:

  1. Работает отлично! Спасибо!

    ОтветитьУдалить
  2. Роман, классно! подскажи как подключить выпадающий список из другого гугл-дока?

    ОтветитьУдалить
    Ответы
    1. Доброго дня.
      На отдельный лист вывести нужный список из нужной таблицы посредством importrange.

      Удалить
  3. Привет. Я нулевый в скриптах. Можешь пояснить, как забрать ИНН или КПП у организации. Я так понимаю, что при запросе он его показывает, но как поместить их в ячейке?

    ОтветитьУдалить
    Ответы
    1. Доброго.
      Согласно справочной документации dadata.ru можно сделать намного больше чем описано в статье - https://support.dadata.ru/ru/knowledge-bases/4/articles/2090-kak-sdelat-vsyo-chto-ugodno-v-podskazkah
      Смотрите как у меня в коде передаются данные в таблицу, на основе кода делайте своё.

      Удалить
    2. Я смотрел код, но у меня не получилось. Новое поле сделал, но при вводе ИНН подсказки не выдает.

      Удалить
    3. Доброго дня.
      Пример dadata.ru - https://codepen.io/dadata/pen/WvmWGX
      В JS комментарий о количестве символов с которого начинаются подсказки.

      Удалить
  4. Роман, здравствуйте!
    Открыл копию листа для ознакомления: Custom menu - скрипт без подсказок, и не могу понять, как скрипт понимает - что при нажатии на кнопку "Ок" - надо отправить данные из заполненной формы на лист "Клиенты"?

    ОтветитьУдалить
    Ответы
    1. Доброго дня.
      Скрипт понимает это благодаря указанию в теге form триггера onsubmit с указанием функции sendData.

      Удалить
  5. Добрый день! Подскажите как сделать, чтобы данные из формы добавлялись не в конец таблицы, а в начало таблицы(добавляя строку и вставляя данные). Насколько разобрался за это отвечает appendRow в строке function sendData(form){
    SpreadsheetApp.getActive().getSheetByName('Клиенты').appendRow([form.name, form.address,form.organisation, form.klass]) 
    Пробовал заменить на insertRow, но ничего не выходит. Уже руки опустились. 

    ОтветитьУдалить
    Ответы
    1. Доброго.
      1. добавляем строку
      https://developers.google.com/apps-script/reference/spreadsheet/sheet#insertRowBefore(Integer)
      2. вставляем данные
      https://developers.google.com/apps-script/reference/spreadsheet/range#setValues(Object)

      Удалить
  6. Добрый день, создал html, в который скопировал содержимое выше из пункта 1, скопировал функции в скрипт из пункта 2 и 3. Добавил пункт меню для вызова функции daData. Окно открывается, но введенные данные в таблицу не сохраняются, лист с именем "Клиенты" создал. Что ещё необходимо чтобы данные попадали в таблицу?

    ОтветитьУдалить
  7. Странно в копии таблицы daData всё работает, а если все функции копирую в другую таблицу, то окно появляется, а данные в лист не вставляються, может надо ещё какие-то права настраивать?

    ОтветитьУдалить