🍏
Google Apps Script + gas-db + HTML を使った TODO アプリ
以前自分が作った ライブラリをこちらで紹介したのですが、使い所がわかりづらいかもと思いまして、TODOアプリのサンプルを作りました。
このサンプルは以下の技術を組み合わせ、簡易的な TODO リストアプリを構築する例です:
- gas-db(Google スプレッドシートをデータベースのように扱うためのライブラリ)
- Google Apps Script のウェブアプリ機能
- Apps Script から返される HTML(クライアントサイド JS)
GitHub Pages などの外部ホスティングは不要で、すべてを GAS 上で提供します。
また、こちらで紹介したコードはリポジトリ内でも載せていますので
完全なコードが気になる方は こちら をご覧ください。
↓↓↓ サンプルコード
↓↓↓ 動作するアプリ
(デプロイしたらURL変わるから動かなくなるかも)
↓↓ スプレッドシート(誰でも編集できます)
概要
- Google スプレッドシート – “データベース” の役割
-
code.js
– サーバーサイドコード(GAS)-
gas-db
を用いてスプレッドシートをCRUD操作 - エントリーポイント(
doGet(e)
)でindex.html
を返す - TODOリストの取得・作成・更新・削除関数を定義
-
-
index.html
– クライアントサイド(UI部分)-
HtmlService
から返される -
google.script.run
を使ってサーバー側の関数を呼び出す
-
手順
1. スプレッドシートの準備
- 新規の Google スプレッドシートを作成します。
- シート名を
Todos
とする(コードと合わせるため)。 - 見出し行に
id
,title
,completed
などを追加。 - スプレッドシートの ID を控えておきます(URL の
/d/
と/edit
の間にある文字列)。
2. GAS プロジェクトを作成
-
script.google.com にアクセスし、新しいプロジェクト を作成する。
- あるいはスプレッドシート画面の「拡張機能」→「Apps Script」でも可。
- プロジェクト名やその他の設定は任意。
3. コードを追加
- gas-db をライブラリとして取り込んでください。 詳細はこちら
-
code.js
の内容をコピーし、GAS プロジェクトに貼り付けてください。(例:ファイル名はCode.gs
など)
/**
* シンプルなTODO管理用のAPIサーバ例
* gas-db を用いてスプレッドシートをCRUD操作します
*/
function debug() {
console.log(getDb())
}
/**
* 1. スプレッドシートおよびシートの取得
* gas-db の書き方に合わせて取得
*/
function getDb() {
// あなたのスプレッドシートID・シート名に適宜書き換えてください
return new gasdb.Spreadsheet()
.from("YOUR_SPREADSHEET_ID")
.at("Todos");
}
/**
* メインエントリーポイント
* HTMLファイル (index.html) を返してWebアプリ化する
*/
function doGet(e) {
return HtmlService.createTemplateFromFile('index') // テンプレート読み込み
.evaluate()
// (オプション)最大幅を広げるなどの設定
.setTitle("TODO App")
}
/**
* すべてのTODOを取得して配列として返す
*/
function getTodos() {
const db = getDb();
// [{id, title, completed}, ...] を全取得
const rows = db.findAll();
// booleanなどの型を適切に扱うために変換しておく例
return rows.map(r => ({
id: r.id,
title: r.title,
completed: (r.completed === true || r.completed === "true")
}));
}
/**
* 新規TODOを作成
*/
function createTodo(title) {
const db = getDb();
// idは簡易的にタイムスタンプ
const newTodo = {
id: new Date().getTime(),
title: title,
completed: false
};
db.insert(newTodo);
}
/**
* TODOの完了フラグをトグル
*/
function toggleTodo(id) {
const db = getDb();
// 既存の1件を検索
const existing = db.pick({ id });
if (!existing) return;
// 反転した値を更新
db.update({ completed: !existing.completed }, { id: existing.id });
}
/**
* TODOを削除
*/
function deleteTodo(id) {
const db = getDb();
db.delete({ id: Number(id) });
}
- 同じプロジェクト内に
index.html
ファイルを追加し、リポジトリ内の同名ファイルの内容をコピーします。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>My TODO App</title>
<!-- Onsen UIのCSSとFontAwesomeをCDNから読み込み -->
<link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsenui.css">
<link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsen-css-components.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
.completed {
text-decoration: line-through;
color: #999;
}
</style>
</head>
<body>
<ons-page>
<ons-toolbar>
<div class="center">TODO List (GAS Web App)</div>
</ons-toolbar>
<div style="padding: 10px;">
<ons-card>
<div class="title">New Task</div>
<div class="content">
<form id="todoForm">
<ons-input id="todoInput" placeholder="New task..." float required></ons-input>
<div style="text-align: right; margin-top: 10px;">
<ons-button type="submit" onclick="createTodo()">Add</ons-button>
</div>
</form>
</div>
</ons-card>
<ons-list id="todoList"></ons-list>
</div>
</ons-page>
<!-- Onsen UIのJavaScriptとVueをCDNから読み込み -->
<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
<script src="https://unpkg.com/onsenui/js/onsenui.min.js"></script>
<script>
document.addEventListener('init', function() {
fetchTodos();
});
function fetchTodos() {
google.script.run.withSuccessHandler(renderTodos).getTodos();
}
function renderTodos(todos) {
const listEl = document.getElementById('todoList');
listEl.innerHTML = '';
todos.forEach(todo => {
const listItem = document.createElement('ons-list-item');
listItem.setAttribute('modifier', 'longdivider');
listItem.innerHTML = ``;
listEl.appendChild(listItem);
});
}
function createTodo() {
const input = document.getElementById('todoInput');
const title = input.value.trim();
if (!title) return;
google.script.run.withSuccessHandler(() => {
fetchTodos();
}).createTodo(title);
input.value = '';
};
function toggleTodo(id) {
google.script.run.withSuccessHandler(() => {
fetchTodos();
}).toggleTodo(id);
}
function removeTodo(id) {
google.script.run.withSuccessHandler(() => {
fetchTodos();
}).deleteTodo(id);
}
</script>
</body>
</html>
-
code.js
の中にある"YOUR_SPREADSHEET_ID"
を先ほど控えたスプレッドシートIDに書き換えます。
4. ウェブアプリとしてデプロイ
- GAS エディタの上部メニュー「デプロイ」→「新しいデプロイ」をクリック。
- 「種類を選択」で 「ウェブアプリ」 を選択。
-
「次のユーザーとして実行」 は「自分」を、「アクセスできるユーザー」 は「全員」または用途に応じて選択。
- 認証無しで誰でもアクセス可能にしたい場合は「全員(匿名ユーザーを含む)」を選択。
- 「デプロイ」を押すと表示される ウェブアプリのURL をコピー。
5. 動作確認
- ウェブアプリのURLをブラウザで開く。
- GAS が
index.html
を返してTODOアプリ画面が表示される。 - 新しいタスクを追加すると、自動でスプレッドシートに行が追加される。
- 作成したタスクの完了チェックや削除ボタンが動作するかを確認。
仕組み
-
doGet(e)
HtmlService
を使いindex.html
を返す。ここがウェブアプリのエントリーポイント。 -
index.html
ページロード時にgoogle.script.run
でサーバーサイドのgetTodos()
を呼び出し、スプレッドシートから取得したTODOデータを表示。
ボタン操作などでcreateTodo()
,toggleTodo()
,deleteTodo()
をサーバー側関数として呼び出し、処理完了後に再取得を実行。 -
サーバーサイド (
code.js
)-
getDb()
がgas-db
のSheet
インスタンスを返し、Todos
シートを操作。 - 各種CRUD操作(findAll / insert / update / delete)を行って TODO データを管理。
スプレッドシートへのアクセス権は「このスクリプトを実行するユーザーの権限」で行うか、匿名で許可する場合は「自分として実行」+「全員(匿名ユーザーを含む)」を設定するなど柔軟に調整できます。
-
よくある質問 (FAQ)
Q. なぜ GitHub Pages でホスティングしないのですか?
- フロントとバックエンドが別ドメインになる場合、ブラウザの同一生成元ポリシーにより CORS 設定が必要となり、Apps Script の標準機能では簡単に
Access-Control-Allow-Origin
を設定できません。 - GAS ウェブアプリとして HTML を提供すれば、同一ドメイン で完結するため、CORS を気にせず実装可能です。
Q. gas-db の他の機能を使いたい場合は?
- このサンプルでは
findAll
,find
,insert
,update
,delete
のみを使っています - スプレッドシートの列を追加し、
title
やcompleted
以外のデータを扱うことも可能です。
Q. デバッグはどうすればいい?
- サーバーサイド (GAS) は
Logger.log()
でログを出せます。エディタの「表示」→「ログ」から確認したり、「実行」→「過去の実行」タブでも参照可能です。 - クライアント(
index.html
)側の JavaScript はブラウザのデベロッパーツールでconsole.log
を使って確認してください。
関連リンク
少ない記述量で スプレッドシートをバックエンドとした アプリを作ることができます!
是非試してみてください!!
Discussion
アクセス権がありません、、、
ありがとうございます!
何かしらの Google アカウントにログインして頂けたら確認できると思いますが、いかがでしょうか?
いくつかのアカウントで試したんですが、無理でした、、
すみません、スプレッドシート自体が閲覧のみになっていたので、編集可能にしてみたのですがどうでしょうか?