【GAS初心者】GASを初めて使ってみてつまづいたところ

## はじめに
2024年あけました。
初詣と同時に、GASで年をあけたので躓いたところをまとめていこうと思います

## つまずき vol.1

### GASで書いたコードをスプシに反映させる時

ちなみに
以下のメソッドは、*コンテナバインド型*　のGASスクリプトでのみ使用することができます

```
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); // スプシを読み込むために使う関数
```


### コンテナバインド型ってなんぞや？

> スプレッドシートやドキュメント、フォームなどのGoogleのサービスに紐づく、Google Apps Scriptのスクリプトのこと

G-suitesのメニュータブを開いた時に出てくるところから使うことができます

![コンテナバインド型.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627753/12f8b532-717b-7a6b-92bc-537d23228526.png)

**▼ メリット・デメリット**
- Googleサービスに紐づけられたサービスでは手軽に使える
- GoogleサービスのIDを指定する必要がない


扱いが少ないうちはGoodですが
たくさんGASを使おうとなると管理コストがかかりますね〜


### スタンドアロン型ってなんぞや？

> Googleサービス全般と連携可能な独立したスクリプト

Google Driveから作成が可能

![874-gas-introduction_01-768x772.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627753/131d5c15-2d8c-a998-ed2a-7ec303f292f9.png)

**▼ メリット・デメリット**
- スクリプトを匿名にすることができたりし、管理がしやすい


IDとURLを指定する必要があるので、
スプシからすぐに使うという手軽さはないですね


## つまずき vol.2

クリスマスあたりから貯金が底を尽きてきて、家計管理を始めたいと思い、スプレッドシートを記述していました。
記入する際に、何度も何度もセルを消しては入力、消しては入力が煩わしく

Webアプリ上で入力して、その値をスプシに書き込めないかと思い、作ってみました。

### やりたかったこと
Document.formsプロパティを使ってform要素を取得したかったのですが

クライアントからサーバー、サーバーからクライアントの通信では
関数や他のデータオブジェクトを渡すことができないみたいです


> ほとんどのタイプは有効ですが、Date、Function、form 以外の DOM 要素は無効です。
https://zenn.dev/agdf/articles/131fa5eb565515

```コード.gs
function totalValue(e) {

  // sheetの範囲を指定する
  let communicationExpenses = e.get('通信費');
  
  // 値を設置する
  sheet.getRange("C6").setValue(communicationExpenses);
}
```


```index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script type="text/javascript">
      function sendText(){
        google.script.run
        .withSuccessHandler()
        .totalValue(new FormData(document.forms["formText"]));
      }
    </script>
  </head>
  <body>
    <h1>家計簿</h1>
    <form name="formText">
        <div class="固定費（毎月）">
          <div class="通信費">
            <label for="通信費">通信費：</label>
            <input type="number" name="通信費" id="通信費">
          </div>
          <div class="水道・光熱費">
            <label for="水道・光熱費">水道・光熱費：</label>
            <input type="number" name="水道・光熱費" id="水道・光熱費">
          </div>
          <div class="Wifi代">
            <label for="Wifi代">Wifi代：</label>
            <input type="number" name="Wifi代" id="Wifi代">
          </div>
          <div class="推し活代">
            <label for="推し活代">推し活代：</label>
            <input type="number" name="推し活代" id="推し活代">
          </div>
        </div>
    </form>
　　</body>
</html>
```

![スクリーンショット 2024-01-08 21.49.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627753/7d131dcf-6569-0312-f3bb-7b4e9454c539.png)

「データオブジェクトを渡すことができない」事実
悲しいよお

### 解決策としては

formの要素を一つずつ取得するやり方です

めちゃくちゃ力技感があるのですが、これで解決しました笑

```コード.gs
// 品目ごとの合計値
function calcItemTotal(currentValue, inputedValue){
  let itemTotal = parseInt(currentValue,10) + parseInt(inputedValue,10);
  return itemTotal;
}

// 通信費
function calculateCommunicationCost(communicationCost) {

  const communicationExpensesRange = sheet.getRange("C6");
  let inputedCommunicationExpensesValue = communicationExpensesRange.getValue();

  if(inputedCommunicationExpensesValue){
    let communicationCostTotal = calcItemTotal(inputedCommunicationExpensesValue, communicationCost);
    communicationExpensesRange.setValue(communicationCostTotal);
  } else {
    inputedCommunicationExpensesValue = 0;
    let communicationCostTotal = calcItemTotal(inputedCommunicationExpensesValue, communicationCost);
    communicationExpensesRange.setValue(communicationCostTotal);
  }
}

// 保険料
function calculateInsuranceFee(insuranceFee) {

  const insuranceFeeRange = sheet.getRange("C7");
  let insuranceFeeValue = insuranceFeeRange.getValue();

  if (insuranceFeeValue){
    let insuranceFeeTotal = calcItemTotal(insuranceFeeValue, insuranceFee);
    insuranceFeeRange.setValue(insuranceFeeTotal);
  } else {
    insuranceFeeValue = 0;
    let insuranceFeeTotal = calcItemTotal(insuranceFeeValue, insuranceFee);
    insuranceFeeRange.setValue(insuranceFeeTotal);
  }
}

// 住居費
function calculateHousingCost(housingCost){

  const housingCostRange = sheet.getRange("C8");
  let housingCostValue = housingCostRange.getValue();

  if (housingCostValue){
    let housingCostTotal = calcItemTotal(housingCostValue, housingCost);
    housingCostRange.setValue(housingCostTotal);
  } else {
    housingCostValue = 0;
    let housingCostTotal = calcItemTotal(housingCostValue, housingCost);
    housingCostRange.setValue(housingCostTotal);
  }
}
```

```index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script type="text/javascript">
      function calculateCommunication(){
        google.script.run
        .withSuccessHandler()
        .calculateCommunicationCost(document.forms['固定費（毎月）'].elements.通信費.value);
      }
      function calculateInsurance(){
        google.script.run
        .withSuccessHandler()
        .calculateInsuranceFee(document.forms["固定費（毎月）"].elements.保険料.value);
      }
      function calculateHousing(){
        google.script.run
        .withSuccessHandler()
        .calculateHousingCost(document.forms["固定費（毎月）"].elements.住居費.value);
      }
      </script>
  </head>
  <body>
  <h1>家計簿→スプシ</h1>
    <div class="固定費（毎月）">
     <form name="固定費（毎月）">
        <div class="通信費">
          <label for="通信費">通信費：</label>
          <input type="number" name="通信費" id="通信費">
          <input type="button" onclick="calculateCommunication()" value="加算">
        </div>
        <div class="保険料">
          <label for="保険料">保険料：</label>
          <input type="number" name="保険料" id="保険料">
          <input type="button" onclick="calculateInsurance()" value="加算">
        </div>
        <div class="住居費">
          <label for="住居費">住居費：</label>
          <input type="number" name="住居費" id="住居費">
          <input type="button" onclick="calculateHousing()" value="加算">
        </div>
     </form>
    </div>
  </body>
</html>
```

## おわりに
人生で初めてGASを書いてみたのですが、普段使っている、スプシやGoogleDocsを自動化できるのは楽しいな〜と思いました。

Gーsuites系を使われている方で、もっと楽にできないかを考えている方には、受けが良さそうな気がした感じです。