Monacaとkintoneで忘年会出欠アプリを作る

楽しい忘年会シーズン到来！しかし幹事さんにとっては大変な時期でもありますね。
そこで今回はkintoneに忘年会の出欠情報を登録するスマホアプリをMonacaで作成してみました。

## アプリの概要

### ログイン画面
kintoneのアカウントを入力してログインを実行します。

![Image uploaded from iOS.png](https://qiita-image-store.s3.amazonaws.com/0/152304/8d5de4b9-d0ca-ccfa-93cf-2167de3ea4ab.png)

### 出欠登録画面
あらかじめkintone側で設定されている忘年会の候補日が表示されます。
参加可能な日程を選択して登録ボタンを押すと、kintoneへの登録が実行されます。

![Image uploaded from iOS.jpg](https://qiita-image-store.s3.amazonaws.com/0/152304/baee22b9-0bf9-1276-8205-fc1cd2c11eac.jpeg)

### 実行結果
スマホアプリから登録された出欠情報がkintoneに蓄積されていきます。

![FireShot Capture 309 - 飲み会日程調整 - レコードの一覧 - https___86glh.cybozu.com_k_40_.png](https://qiita-image-store.s3.amazonaws.com/0/152304/6a08f03d-6f48-972a-7e6c-94d0de633a08.png)

## Monacaとkintoneの連携方法
Monacaとkintoneの連携は [kintone REST API](https://developer.cybozu.io/hc/ja/categories/200147600-kintone-API) で行いますが、このAPIをラップしてより簡単に使えるようにしたライブラリ「[kintone Utility Library for JavaScript](https://github.com/kintone/kintoneUtility)」がありますので、こちらを使って開発していきます。

## kintone Utility Library for JavaScriptのインストール
kintone Utility Library for JavaScript は、Monacaのサービス連携画面からでもインストールできるのですが、少し古いバージョンのものがインストールされるようです（2017年12月現在）。
今回は最新のkintone Utility Libraryを使いたいので、[githubから](https://github.com/kintone/kintoneUtility) docs 以下のjsファイル（kintoneUtility.js または kintoneUtility.min.js）を入手し、Monaca IDEにアップロードして使います。


## kintone側の設定
アプリストアに「飲み会日程調整」というそのものずばりなテンプレートがありますので、そちらをベースにしてkintoneアプリを登録します。

### アプリIDの確認
「飲み会日程調整」アプリを作成すると、ブラウザのアドレスバーに以下のようなURLが表示されます。
```
https://サブドメイン.cybozu.com/k/1/
```
一番後ろの数字（上記の例では1）が、アプリIDになります。

### フォームの編集
フォームの編集画面を見ると、「飲み会日程調整」アプリには自動入力される名前、出席可能な日、コメントの3種類のフィールドがあることがわかります。

![FireShot Capture 310 - アプリの設定 - https___86glh.cybozu.com_k_admin_app_flow_app=41#section=form.png](https://qiita-image-store.s3.amazonaws.com/0/152304/e8ac2394-3c9d-8cf7-c8b7-3845f93333cb.png)

「出席可能な日」フィールドの設定画面を開くと、一番下に「フィールドコード」という項目が表示されます。
フィールドコードは、フィールドを識別するためのIDです。
デフォルトでは「複数選択」という値が入っていますが、これではわかりづらいので、「date」に変更します。

![FireShot Capture 304 - アプリの設定 - https___86glh.cybozu.com_k_admin_app_flow_app=39#section=form.png](https://qiita-image-store.s3.amazonaws.com/0/152304/424b8058-3e0c-af83-3663-e17079045649.png)

同様に、「コメント」フィールドのフィールドコードも「comment」に変更しておきます。

最後に、忘れずに画面右上にある「アプリを更新」ボタンを押してください。これでkintone側の設定は完了です。

## Monaca側のソースコード
ソースコード全文は以下の通りです。画面はOnsen UIを使って実装しています。

```html:index.html
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
  <script src="components/loader.js"></script>
  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="css/style.css">
  <!-- kintone Utility Libraryの読込 -->
  <script src="js/kintoneUtility.js"></script>
  <script>
    // kintoneのアプリ情報
    let appInfo = {
      id: 1,  // 自分のアプリIDに変更してください
      domain: 'サブドメイン.cybozu.com'  // 自分のサブドメインに変更してください
    };
    
    // ログイン処理
    function login() {
      let name = document.querySelector('#name').value;
      let pass = document.querySelector('#pass').value;
      
      // ドメイン情報の設定
      kintoneUtility.rest.setDomain(appInfo.domain);
      // 認証情報の設定
      kintoneUtility.rest.setUserAuth(name, pass);
      
      // kintoneアプリのフォーム情報を取得
      kintoneUtility.rest.getFormFields({
        app: appInfo.id
      })
      .then((response) => {
        return document.querySelector('#navi').pushPage('entry.html', {data:response});
      })
      .then(initForm)
      .catch((error) => {
        console.log(error);
      });      
    }
    
    // 出欠登録画面の初期処理
    function initForm(page) {
      // 「出席可能な日」をフィールドの項目を取得
      let options = page.data.properties.date.options;
      Object.keys(options).forEach((key, index) => {
        // 「参加可能日」の見出しの下にons-list-item要素を挿入
        ons.createElement(
          `<ons-list-item tappable>
            <label class="left">
              <ons-checkbox input-id="check-${index}" name="date" value="${key}"></ons-input>
            </label>
            <label for="check-${index} class="center">
              ${key}
            </label>
          </ons-list-item>`,
          {
            append: page.querySelector('#formList'),
            insertBefore: page.querySelector('#title2')
          }
        );
      });
    }
    
    // 登録
    function entry() {
      // kintoneに登録するデータ
      let data = {
        "date": {
          // 複数選択項目は配列形式で指定
          value: Array.prototype.map.call(
            document.querySelectorAll('[name="date"]:checked'),
            (elm) => { return elm.value; }
          )
        },
        "comment": {
          value: document.querySelector('#comment').value
        }
      };
      
      // レコードの登録
      kintoneUtility.rest.postRecord({
        app: appInfo.id,
        record: data
      }).then((r) => {
        console.log(r);
        alert("登録しました");
      }).catch((e) => {
        alert(JSON.stringify(e));
      });
    }
  </script>
</head>
<body>
  <ons-navigator id="navi" page="login.html"></ons-navigator>
  
  <!-- ログイン画面 -->
  <template id="login.html">
    <ons-page>
      <ons-toolbar>
        <div class="center">ログイン</div>
      </ons-toolbar>
  
      <div class="login-form">  
        <ons-input type="text" modifier="large underbar" placeholder="アカウント名" value="" id="name"></ons-input>
        <ons-input type="password" modifier="large underbar" placeholder="パスワード" value="" id="pass"></ons-input>
        <ons-button id="loginButton" modifier="large" onclick="login()">ログイン</ons-button>
      </div>
    </ons-page>
  </template>
  
  <!-- 登録画面 -->
  <template id="entry.html">
    <ons-page>
      
      <ons-toolbar>
        <div class="center">出欠登録</div>
      </ons-toolbar>
      
      <ons-list id="formList">
        <ons-list-header id="title1">参加可能日</ons-list-header>
        
        <ons-list-header id="title2">コメント</ons-list-header>
        <ons-list-item>
          <ons-input type="text" modifier="underbar" id="comment"></ons-input>
        </ons-list-item>
    
      </ons-list>
  
      <div style="text-align:center;margin:20px">
        <ons-button onclick="entry()" modifier="large">登録</ons-button>
      </div>
      
    </ons-page>
  </template>
</body>
</html>

```

要点を絞って、kintone Utility Libraryの使い方を解説します。

### ドメイン情報の設定
```
kintoneUtility.rest.setDomain('kintoneドメイン名')
```
まずはじめに、接続先のkintoneドメインを指定します。`xxxxx.cybozu.com` のような形式になるはずです。

### 認証情報の設定
```
kintoneUtility.rest.setUserAuth('ユーザー名', 'パスワード')
```
kintoneのユーザー名とパスワードを指定して、ログインを実行します。


### kintoneアプリのフォーム情報を取得
```
kintoneUtility.rest.getFormFields({ app:アプリID })
```
アプリIDを指定して、アプリのフォーム情報を取得します。戻り値はPromiseです。
今回は「出席可能な日」フィールドの情報を取得するためにこの処理を行っています。

### レコードの登録
```
kintoneUtility.rest.postRecord({
   app: アプリID,
   record: 登録するデータ
})
```
アプリIDと登録するデータを指定して、kintoneへの登録を実行します。戻り値はPromiseです。
recordにはオブジェクト形式で登録データを指定しますが、このときデータの指定形式にはルールがあります。

#### 単一データを格納するフィールドの場合
```
"フィールドコード": {
   value: 値
}
```

#### 複数選択形式のデータを格納するフィールドの場合
```
"フィールドコード": {
   value: [値1, 値2, …]
}
```

配列形式で値を指定するのがコツです。上記のソースコードでは、NodeList形式から配列形式に変換しています。


## おわりに
kintoneは、自分でマスター画面を作らなくて良いので便利ですね。
Monacaとの連携もkintone Utility Libraryを使うととても簡単に実装できることがわかりました。
今回はログインと登録処理だけでしたが、他にも様々な処理を行うことができるので、[kintone Utility Libraryのガイド](https://github.com/kintone/kintoneUtility/blob/master/guides/rest_doc.md)を参考にしてみてください。