kintoneの内部パラメータ「フィールドID」を使いこなす

# kintoneのフィールドIDとは？

kintoneではフィールドの判別に「フィールドコード」「フィールド名」を使いますが、
もう一つ、内部パラメータとして「フィールドID(仮称)」を持っています。

普段表には現れませんが、デバッグコンソールでHTMLを見ると、
こんな風にclass名の一部に使われたりしています。

```html
<div class="control-gaia control-decimal-field-gaia field-5525625" >
<div class="control-label-gaia label-5525625" >
<div class="control-value-gaia value-5525625" >
```

<img width="619" alt="スクリーンショット 2019-05-16 15.56.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24333/b767b1b3-2d62-5d6b-7015-3241697dea13.png">

公開されているJavaScript APIではないので、今後のkintoneバージョンアップで動かなくなる可能性はありますが、現状確認できている挙動としては

* フィールドコード：フィールドID = 1:1
* フィールドコードを変えてもフィールドIDは変わらない
* フィールドIDは自動採番で変更不可能

って感じ。

そして、レコード編集画面でフィールドのDOMを取得するときなんかは、
JavaScript APIではうまく取れないので
このフィールドIDをうまく使ってやると、より高度なhackができるわけです！
（繰り返しますが、非公式カスタマイズなので、動かなくなるリスクを踏まえて自己責任で！）

# window.cybozuオブジェクト

実は、`window.kintone`とは別に`window.cybozu`というグローバルオブジェクトがあり、
こうしてやると超便利な`fieldList`オブジェクトが取れることを、同僚の @t2kojima が発見してくれました！

```js:普通のフィールド
cybozu.data.page.FORM_DATA.schema.table.fieldList
```

```js:サブテーブル
cybozu.data.page.FORM_DATA.schema.subTable
```

```js:サブテーブル内のフィールド
cybozu.data.page.FORM_DATA.schema.subTable[サブテーブルのフィールドID].fieldList
```


<img width="448" alt="スクリーンショット 2019-05-16 16.04.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24333/5f406fce-9191-60d0-7f27-40ef8d937af4.png">

`fieldList`オブジェクトの`key`と`value.id`が、どちらもフィールドID。
`value`の中にはフィールドコードやらフィールド名やら、
他にもデフォルト値、単位、必須制約などなど宝の山が入っております！

# fieldListを使った例

## 基本
`Object.values()`で配列にしておくと、その後扱いやすいです。

### 普通のフィールドだけの場合

シンプルにこれでOK

```js
const fields = Object.values(cybozu.data.page.FORM_DATA.schema.table.fieldList)
```

### サブテーブルを含む場合

ちょっと複雑になるのですが、基本はこの3パターンになると思います。あとは用途によって使い分けてください。

#### テーブル本体をすべて抽出（テーブル内フィールドは無視）

```js:
const fields = Object.values(cybozu.data.page.FORM_DATA.schema.subTable)
```
#### テーブル内フィールドだけを、全テーブル横断して抽出

```js:
const subTables = Object.values(cybozu.data.page.FORM_DATA.schema.subTable)
const fields = subTables.flatMap(t => Object.values(t.fieldList))
```

#### 普通のフィールド・テーブル本体・テーブル内フィールドの3種を同列に抽出

```js:
const mainFields = Object.values(cybozu.data.page.FORM_DATA.schema.table.fieldList)
const subTables = Object.values(cybozu.data.page.FORM_DATA.schema.subTable)
const subFields = subTables.flatMap(t => Object.values(t.fieldList))
const fields = [...mainFields, ...subTables, ...subFields]
```

## 応用

以下、↑のいずれかの方法で`fields`配列が作られている前提で進めます。

### フィールドコードからフィールドIDを調べる

```js
fields.find(_ => _.var === '支払サイト').id
// "5525625"
```


### フィールド名からフィールドIDを調べる

```js
fields.find(_ => _.label === 'レコード番号').id
// "5525614"
```

### フィールドコードをキーにフィールド情報を引くオブジェクトを作る

```js
const fieldMap = fields.reduce((map, field) => ({ ...map, [field.var]: field }), {})
fieldMap.支払サイト.id
// "5525625"
fieldMap.支払サイト.properties.unit
// "日後"
```

### DOM操作でフィールドに任意の値を設定する

```js
const fieldId = fieldMap.支払サイト.id
$input = document.querySelector(`.value-${fieldId} input`)
$input.value = 30
```

# 類似オブジェクト

`SCHEMA_DATA`という似たようなオブジェクトがあって、似たように使えるんですが、こっちはルックアップ・関連レコードフィールドの詳細まで入っています。

```js
cybozu.data.page.SCHEMA_DATA.table.fieldList
```

# 終わりに
しつこいですが、あくまで自己責任で使ってくださいね！(笑)
よく忘れるので、自分用メモも兼ねて書きましたー。

ではまた！