kintoneのユーザー選択フィールドに重複禁止をつけてみた

# はじめに

kintoneのフィールドで重複禁止設定ができるのは「文字列1行」と「数値」のみ！
つまり、他のフィールドで重複チェックしたい場合はカスタマイズをする必要があります。

ということで、
今回は**「ユーザー選択フィールド」**に重複禁止処理をつけてみました

# デモ

同じユーザーでレコードが複数登録された場合、エラーが出るようになっています
※ レコード編集にも対応
![checkUserField1.gif](https://qiita-image-store.s3.amazonaws.com/0/153051/4d70bbaa-a74c-c6ad-31b3-3a9551bec0ce.gif)

↓ 複数人にも対応させています！
![checkUserField2.gif](https://qiita-image-store.s3.amazonaws.com/0/153051/4c376cf5-ef5a-df5c-33d2-6090ad0059b5.gif)

# 利用シーン

**ユーザー選択フィールドを重複禁止にしたい時ってなんだろな～**
といろいろユースケースを考えましたが、すぐに思いつくところだと

* 社員名簿
* 1人1日1レコードの日報
* アンケート/抽選アプリ

ぐらいが限界でした。。
まぁ、ユースケースなんて気にしない！作りたいから作る！

# 仕組み

kintone REST API を使って、自身のアプリから
**「ユーザー選択フィールドに自分が登録されているレコードがあるか」**を確認しています。

上記の条件をクエリに書いて、GETをした際のレスポンスに

* レコードがない → レコード保存ができる
* レコードがある → エラー表示

という動きにしています。~~複数人対応させた影響でクエリ部分がやや複雑になりました(；・∀・)~~

（18/10/12 追記）
コメントをいただき、シンプルに記述できました！！ありがとうございます！

# コード

[GitHub](https://github.com/RyBB/kintoneCustomize/tree/master/Check_Duplicate_UserSelectField)に置いてあります。

```Javascript
(function() {
  'use strict';

  kintone.events.on(['app.record.create.submit', 'app.record.edit.submit'], function(event) {
    const userField = event.record['userselect'].value;
    const recordId = kintone.app.record.getId();
    let query = '';

    // ユーザー選択フィールドが空のときは処理をやめる
    if (!userField.length) {
      return;
    }

    // レコード編集時 (=レコードがすでにある時) はクエリ文追加
    if (recordId) {
      query = '$id != ' + recordId + ' and ';
    }

    // ユーザー選択フィールド用クエリ(複数人対応)
    query += 'userselect in ("' + userField.join('", "') + '")';

    const param = {
      'app': kintone.app.getId(),
      'query': query,
    };

    // PromiseでREST(GET)を実行
    return kintone.api(kintone.api.url('/k/v1/records'), 'GET', param)
      .then(function(resp) {
        if (resp.records.length) {
          let errMessage = resp.records[0]['userselect'].value[0].name + 'が重複しています！';
          event.record['userselect'].error = errMessage;
        }
        return event;
      })
      .catch(function() {
        // error
        event.error = '予期せぬエラーが発生しました！';
        return event;
      });
  });

  // userselectフィールドが変更されたときはエラー表示を消す
  kintone.events.on(['app.record.create.change.userselect', 'app.record.edit.change.userselect'], function(event) {
    event.record['userselect'].error = null;
    return event;
  });
}());

```

また、REST APIを利用すると非同期処理になるので、Promiseを使って同期処理にしています。

# 解説

## レコード編集の判定

レコード追加時と編集時で重複の判定が変わってくるため (編集の場合は必ず1つレスポンスがある)、「編集時」という判定が必要になります。

追加時と編集時の違う点は、
**「レコードが作られたかどうか → <font color="red">レコードIDがあるかどうか</font>**」
で判断できます！

なので、
レコードIDがある場合、クエリに「そのレコードIDを除外する」部分を追加しています。

```javascript
    const recordId = kintone.app.record.getId();
    // ~~~
    // レコード編集時 (=レコードがすでにある時) はクエリ文追加
    if (recordId) {
      query = '$id != ' + recordId + ' and ';
    }
```

## 複数人対応

~~複数人に対応する場合は、ユーザー選択フィールド(配列)をループさせます。
最後にカンマが残ってしまうので、削除して、閉じ括弧「)」を追加します。~~

（18/10/12 追記）
仕組みは同じですが、joinメソッドを使えばループがシンプルに記述できます

```javascript
query += 'userselect in ("' + userField.join('", "') + '")';
```

ちなみに、ループさせてごりごりしていたのがこちら。

```javascript
    // ユーザー選択フィールド用クエリ(複数人対応)
    query += 'userselect in (';

    for (let i = 0; i <= (userField.length - 1); i++) {
      query += '"' + userField[i].code + '",';
    }
    // 最後のカンマを削除して閉じる
    query = query.slice(0, -1);
    query += ')';
```

## エラー表示

以下のように書くことで、kintoneのエラー表示を利用することができます！

フィールドの下側に表示させたい場合

```JavaScript
event.record['フィールドコード'].error = 'エラー';
```

画面上部に表示させたい場合

```JavaScript
event.error = 'エラー';
```

※ どちらも return event等をしてイベントを返す必要があります！

# おわりに

こういった制限系のカスタマイズは説明コストが下がるのでかなりおすすめです！
(**1人1レコード！**と説明しても、聞いていなかったとかで複数登録されるし、、汗)

kintoneの標準機能になくても、カスタマイズをすればできることは山ほどあります！
まずは身近な悩みから解消してみてはどうでしょうか！

kintoneのカスタマイズで困ったことがあれば cybozu developer network のコミュニティで質問してみると良いですよ～！

それでは！≧(+･` ཀ･´)≦