７．ページ内検索を導入する

# 今日の目標：一覧画面内で検索できるようにする

## 0．前回の振り返り
https://qiita.com/LoAMiat/items/cf5cb7454c87df233e33

GoogleDriveのフォルダを作成し、画像ファイルを保存できるようになりました。

## 1．一覧画面で画面を検索する
こういう感じのみための検索用の入力欄と呼び出し処理を記述します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782982/0fdf31b5-cfe7-8ca3-4499-6bd1b8b471b4.png)

``` html:List.html
    <script>
      function search() {
        const keyword = document.getElementById("keyword").value;
        alert(keyword);
        const url = '<?= deployURL ?>?type=detail-Search&keyword=' + keyword;
        window.top.location.href = url;
      }
    </script>
  </head>
  <body>
    <header>
      <a href="<?= deployURL ?>">
        <?= header ?>
      </a>
    </header>
    <div class="cat-profile" style="max-width: 600px;">
      <h3 class="text-center m-4"><?= title ?> (<?= rows ?>匹)</h3>
      <form>
        <input type="text" id="keyword" name="keyword" class="detailvalueInput search"/>
        <button type="button" class="catBtn btn btn-outline-primary" onclick="search();" value="<?= keyword ?>">検索</button>
        <span class="gridParent">
          <? output._ = formHTML ?>
        </span>
```
``` javascript:handler.gs
/**
 * 初期表示画面ハンドリング
 */
function doGet(e) {
  // パラメータ取得
  const type = e.parameter.type;
  const keyword = e.parameter.keyword;

  let htmlOutput;
  // キーワード検索結果一覧画面
  if( type === 'detail-Search'){
    htmlOutput = initSearch(e, keyword);
  }

  return htmlOutput;
}
```

## 2．キーワード検索をできるようにする
検索結果を`getDataRange`を使って検索した時と同様のオブジェクト形式に変換していきます。
`getRange`と`getCell`を利用して、1行ずつ取得した結果を1列ずつループしていきます。

``` javascript:List.gs
/**
 * キーワード検索結果画面表示
 */
function initSearch(e, keyword) {
  rowNumCat = 0;
  let htmlOutput;
  let cacheVal = cache.get(keyword);
  // キャッシュに値が残っているか確認
  if( !cacheVal && cacheVal !== null){
    htmlOutput = cacheVal;
  } else {
    // スプレッドシート検索
    const cats = getSearchedRecords(keyword);

    // 表示画面、変数定義
    const template = HtmlService.createTemplateFromFile('CatList');
    template.deployURL = ScriptApp.getService().getUrl();
    template.formHTML = setListHTML(e, cats, 'List');
    template.keyword = keyword;
    // html生成
    htmlOutput = template.evaluate();
    htmlOutput.setTitle('保護猫一覧');
    htmlOutput.addMetaTag('viewport', 'width=device-width, initial-scale=1');

    // 検索結果をキャッシュに残す
    cache.put( keyword, htmlOutput );
  }
  return htmlOutput;
}

/**
 * キーワード検索
 */
function getSearchedRecords(keyword) {
  const ss = SpreadsheetApp.openByUrl(catMasterURL);
  const sheet = ss.getSheetByName('猫マスタ');
  const ranges = sheet.createTextFinder(keyword).findAll();

  // 行番号を取得し、その行のすべての値を取得する
  let rows = [];
  let records = [];
  const labels = sheet.getRange("'猫マスタ'!A1:AA1");
  for(const range of ranges){
    const rowNo = range.getRow();
    // 1行内で複数回検索に一致する可能性がある
    if( rows.includes(rowNo) ){
      continue;
    }else{
      rows.push(rowNo);
      // CatMasterLines = "'猫マスタ'!A:AA";
      const rangeArea = "'猫マスタ'!A" + rowNo + ":AA" + rowNo;
      const values = sheet.getRange(rangeArea);

      const record = {};
      for(let i=1; i<=values.getNumColumns(); i++) {
        record[labels.getCell(1, i).getValue()] = values.getCell(1, i).getValue();
      }
      records.push(record);
    }
  }
  return records;
}
```
---
今日はここまで