【スプレッドシート】GASによる自動入力2

経緯
支援管理表、ほぼ毎日書く必要があるのに書く項目多過ぎる問題
しかも Googleフォームで送信された内容とほぼ同じ事を書く欄もそこそこある。
フォーム > 回答収集スプレッドシート > 管理表スプレッドシート
回答収集のブックは利用者ごちゃ混ぜで入ってくる。
管理表のブックは個人個人で別のブックがある。
よって、一つのブックに纏める訳にもいかない。
つまり回答収集スプシを参照して管理表にぶち込む仕組みが必要だ !

▼前回
【スプレッドシート】GASによる自動入力

自動入力する項目を増やす

前回は名前や日付の条件を伴わない値の入力と、条件に合う値を入力する学習目標を入れられるようにしてみた。
そこで今回は条件付きの入力項目を増やしてみる。

HTML
function autoInput() {
  const recordSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();

  const userName = ["手素斗 太郎", "手素斗太郎", "手素斗 太郎", "手素斗", "テスト タロウ"];

  /* 日報取得 */
  // come: 通所、return: 退所
  const reportSheet = SpreadsheetApp.openById("[回答収集ブックのID]");
  const comeSheet = reportSheet.getSheetByName("通所日報シート名");
  // const returnSheet = reportSheet.getSheetByName("退所日報シート名");

  const comeLastRow = comeSheet.getLastRow();
  // const returnLastRow = returnSheet.getLastRow();

  // シートのデータを2次元配列で取得
  // 通所時: A:R(18列) --- 退所時: A:O(15列)
  const comeData = comeSheet.getRange(comeLastRow - 19, 1, 20, 18).getValues();
  // const returnData = returnSheet.getRange(returnLastRow - 19, 1, 20, 15).getValues();

  // 利用者名
  recordSheet.getRange("I7").setValue(userName[0]);

  // 学習年月日 = シート名
  const recordDate = recordSheet.getSheetName();
  recordSheet.getRange("L7").setValue(recordDate);

  /* 学習目標 と 予定 */
  let objectives = null;
  let schedule = null;
  for(let j = 0; j < userName.length; j++){
    for (let i = 1; i < comeData.length; i++) {
      const name = comeData[i][3]; // 名前欄
      const dateVal = comeData[i][4]; // 日付欄

      const dateStr = Utilities.formatDate(dateVal, "JST", "yyyy年M月d日"); // 日付を文字列に変換

      if (name === userName[j] && dateStr === recordDate) {
        objectives = comeData[i][15]; // 学習目標欄
        schedule = comeData[i][16]; // 予定欄
        break;
      }
    }
  }

  if (objectives !== null) {
    // 学習目標
    objectives += "\n";
    objectives += schedule;
    recordSheet.getRange("B9").setValue(objectives);

    // 予定
    const allSche = Array(3).fill([schedule]);
    recordSheet.getRange("B13:B15").setValues(allSche);
  }
}

前回から引き続きということで全文を表示しておいた。細々とした点が前回と異なっている。
今回使うのは /* 学習目標 と 予定 */ 以降のみなので改めて書き出してみる。

/* 学習目標 と 予定 */
  let objectives = null;
  let schedule = null;
  for(let j = 0; j < userName.length; j++){
    for (let i = 1; i < comeData.length; i++) {
      const name = comeData[i][3]; // 名前欄
      const dateVal = comeData[i][4]; // 日付欄

      const dateStr = Utilities.formatDate(dateVal, "JST", "yyyy年M月d日"); // 日付を文字列に変換

      if (name === userName[j] && dateStr === recordDate) {
        objectives = comeData[i][15]; // 学習目標欄
        schedule = comeData[i][16]; // 予定欄
        break;
      }
    }
  }

  if (objectives !== null) {
    // 学習目標
    objectives += "\n";
    objectives += schedule;
    recordSheet.getRange("B9").setValue(objectives);

    // 予定
    const allSche = Array(3).fill([schedule]);
    recordSheet.getRange("B13:B15").setValues(allSche);
  }

まず変更点について
以前使っていた matchedValue という変数は保持したい値が増えたため、名前を変更して objectives とした。目標という意味らしい。初めは goal としていたが、objectives の方が学習目標という意味合いが強いみたい。

新たに schedule という変数を宣言。
comeData[i][16] を保持する部分は特に言うことも無いので割愛。

セルに値を入力する部分について
if() の条件はまたあとで考える事として。学習目標には 目標の文字列 + 改行 + 予定 を組み合わせてセルに入力している。
予定は入力する欄が複数ある想定のため、allSche という 2次元配列を宣言して全要素に schedule を格納している。
実際は下記のような状態になっている。

// const allSche = Array(3).fill([schedule]); の結果

const allSche = [
  [schedule],
  [schedule],
  [schedule]
]

初めは const allSche = [[schedule], [schedule], [schedule]]; と宣言していたのだが、すっきりしてないよね。
という訳で天下の ジプト先生(chatGPT) に質問したところ、良い感じの宣言方法を持ってきてくれた。のですが、GAS初心者の私、読むのに時間がかかる。で結局、過去の知識を元に理解度の低いまま妥協した形が ↑アレ。

// ジプト先生が提示した宣言
const hensuu = "テスト";
const rows = 3;  
const x = Array(rows).fill().map(() => [hensuu]);

// 私の宣言(比較用)
const allSche = Array(3).fill([schedule]);

行けたんだから良いんだよ。Array() と fill() の意味は大体わかってるから。map() は~、はい。
わかんねぇやつは使わないに越したことないから !

セルに入力する際の条件を考える

てか条件要らなくね !?
必要無い気もするけど、学習目標が空欄で送信された時とかにスプシをより見やすくするために条件付けるか。

/* 通所日報 (学習目標/予定) */
let objectives = "";
let schedule = "";

/* 中略 */

// 学習目標
if(objectives !== "") objectives += "\n";
if(schedule !== "") objectives += schedule;
recordSheet.getRange("B9").setValue(objectives);

// 予定
const allSche = Array(3).fill([schedule]);
recordSheet.getRange("B13:B15").setValues(allSche);

まず、些細な事だけど null が好きじゃないので “” に変更。

で、学習目標と予定を囲んでいた if文を取り払って個別に if() を追加した。こうすることで 2重 3重に if() で囲む必要が無くなり、見辛さを軽減できる…できてるよね ?
加えて、学習目標が空欄なのに改行されるというような状況に柔軟に対応できる。

一応、if ( [変数名] !== “” ) の部分は if( [変数名] ) と書くこともできる。できるのだが、10年後にこのコードを見て条件を難なく読めるか怪しいな…という考えから敢えて『 !== “” 』を付けている。
何故変数名だけで条件分岐ができるかというと、if文は括弧()の中身が true か false かで条件分岐を判断しており、空文字(“”) は false、それ以外の文字は true として区別されるためである。if(false) である場合、if文の中身の処理は実行されない。
よって、if(“”) は実行されない。

let a, b, c, d;
let x = "";
if(false) {
  a = 1;
  Logger.log(a);
}
if("") {
  b = 2;
  Logger.log(b);
}
if(x) {
  c = 3;
  Logger.log(c);
}
if(x === "") {
  d = 4;
  Logger.log(d);
}

// 実行結果: 4
// 上 3つの if文の中の処理は実行されない。4つ目の if文は文字の比較結果が正しいため実行される。

▲こんな感じ

他にも三項演算子を使う方法等があるはずだが、可読性は if() と大差無くかつ私には if() の方が無意識に書けたため採用していない。
また、ジプト先生によると、&& や || のような演算子を使った記述方法もあるらしい。詳しくはよくわからぬ。

もう片方のシートからも自動入力

変数名どうしよう。ググれば良いか。
え~と振り返りは、look back だと収まり悪いかな。単語が良いな。じゃあ reflection にするか。
できた事(結果) は What I was able to do 長いわ ! えー、What I did でもない、doing …しっくりこない。
せや、達成と置き換えてみたら ? achievement
ふぅぅぅぅ、難しいよ英単語 ! clear とかで良いか ? もう !
と思って、よく考えたら入力する欄は結果という項目だった。じゃあ result で良いか。

コードを載せようかとも思ったのですが、通所日報とほぼ変わらないため敢えて書くこともなかった。

// 学習目標
if(objectives !== "" || schedule !== "") objectives += "\n";
if(schedule !== "") objectives += schedule;
recordSheet.getRange("B9").setValue(objectives);

// よく考えたらこの方が良い事に気が付く。
// いや、それじゃ意味ないか。▼こうした方が良いのか。
if(objectives !== "" || (objectives === "" && schedule !== "")) objectives += "\n";
// こうすると大変長くなるから好みではないし、ここまではしなくても良いか ??

結局、上記の条件は採用せず、見出し “セルに入力する際の条件を考える” での条件のまま使うことにした。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA