Handsontable 使い方メモ３（カラム・セルオプション）

[基本](http://qiita.com/opengl-8080/items/ac19deec388c357cd498)
[グリッドのオプション](http://qiita.com/opengl-8080/items/9d25e106ff48b66cb908)
[メソッド](http://qiita.com/opengl-8080/items/e756af444147771fab18)

※全てのオプションは網羅していません。

全てのオプションを確認したい場合は、 [公式ドキュメント](http://docs.handsontable.com/0.24.1/tutorial-introduction.html) を参照。

# カラムオプション
## 基本
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'text'
        }
    ]
});
```

- カラムのオプション指定は、 `columns` に配列を渡し、列番号に対応する要素にオブジェクトを渡すことで設定する。

## `type`：カラムの型を指定する
### `text`：テキスト
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'text'
        }
    ]
});
```

- デフォルトは `text`。
- 文字列入力になる。
- 基本、何でも入力可能。
- 文字は自動で左寄せになる。

### `numeric`：数値
```js
var grid = document.getElementById('grid');

var table = new Handsontable(grid, {
    columns: [
        {
            type: 'numeric'
        }
    ]
});
```

![handsontable.JPG](https://qiita-image-store.s3.amazonaws.com/0/28302/9d09e8cf-e589-dab4-1f9c-5ecd4770cc8f.jpeg)

- 数値の入力のみ可になる。
- 数値以外を入力するとセルが赤くなる。
- 文字は自動で右寄せになる。

#### フォーマットする
```js
var grid = document.getElementById('grid');

var table = new Handsontable(grid, {
    columns: [
        {
            type: 'numeric',
            format: '0,000.99'
        }
    ]
});
```

![handsontable.JPG](https://qiita-image-store.s3.amazonaws.com/0/28302/eae5a197-f543-50f3-396e-5ee063969e2a.jpeg)

- `format` でフォーマットを指定できる。
- 全部は確かめてないけど、 [Numeral.js](http://numeraljs.com/) にあるフォーマットが使えるっぽい。

### `checkbox`：チェックボックス
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    data: [
        [true],
        [false],
        [true]
    ],
    columns: [
        {
            type: 'checkbox'
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/5a79f38b-420d-9204-2e5a-7e368c3df85f.jpeg)

- `checkbox` でチェックボックスになる。
- `true` でチェックがオンになり、 `false` でオフになる。

#### `checkedTemplate`, `uncheckedTemplate`：オン・オフの値を変更する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    data: [
        ['no'],
        ['yes'],
        ['no']
    ],
    columns: [
        {
            type: 'checkbox',
            checkedTemplate: 'yes',
            uncheckedTemplate: 'no'
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/466377ea-82a7-43ff-7685-80e910ad606a.jpeg)

- `checkedTemplate` でオンとなる値を、
- `uncheckedTemplate` でオフとなる値を指定できる。

#### `label`：ラベルを表示する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    data: [
        [false],
        [true],
        [false]
    ],
    columns: [
        {
            type: 'checkbox',
            label: {
                value: 'チェックボックスやで'
            }
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/d34fbcea-ab03-58e4-361a-33928faa41f7.jpeg)

- `label` の `value` でチェックボックスの横に表示させる文字列（ラベル）を指定できる。
- デフォルトはチェックボックスの右側に表示される。
- 左に表示させたい場合は、 `position` に `before` を指定する。

```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    data: [
        [false],
        [true],
        [false]
    ],
    columns: [
        {
            type: 'checkbox',
            label: {
                value: 'チェックボックスやで',
                position: 'before'
            }
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/78cba491-9f66-c249-3600-8ffc38520b9f.jpeg)

- デフォルトは `after` なので右側に出てる。

### `autocomplete`：オートコンプリート
#### 基本
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'autocomplete',
            source: ['one', 'two', 'three', 'four', 'five']
        }
    ]
});
```

![handsontable.gif](https://qiita-image-store.s3.amazonaws.com/0/28302/3135662d-8399-5d27-e545-f8f19c822743.gif)

- `type` を `autocomplete` にして `source` を指定すると、オートコンプリートが表示されるようになる。
- 候補の検索は、部分一致で行われる。
- デフォルトは `source` で定義した値以外も入力できる。

#### `strict`：入力できる値を制限する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'autocomplete',
            source: ['one', 'two', 'three', 'four', 'five'],
            strict: true
        }
    ]
});
```

![handsontable.gif](https://qiita-image-store.s3.amazonaws.com/0/28302/028950fb-d320-d6ab-33ae-004f6946022f.gif)

- `strict` を `true` にすると、 `source` で挙げた値しか入力が許可されなくなる。
- オートコンプリートの補完途中で `Enter` などで入力を終了させると、そのとき選択されていた項目で自動的に入力値が埋め込まれる。
- `source` にない値を無理やり入力すると、セルの背景色が赤くなる。

#### 入力できる値を完全に制限する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'autocomplete',
            source: ['one', 'two', 'three', 'four', 'five'],
            strict: true,
            allowInvalid: false
        }
    ]
});
```

![handsontable.gif](https://qiita-image-store.s3.amazonaws.com/0/28302/e5288f4b-47dd-a337-541a-f308dec2d4bd.gif)

- `allowInvalid` に `false` を設定すると、 `source` で指定した値以外は全く入力できなくなる。
    - `allowInvalid` 自体は他の `type` でも使用可能。
- `Enter` などで入力を終了させようとしても、終了させられなくなる。
- `Esc` で入力を終了させられる。

#### `source` に関数を指定する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'autocomplete',
            source: function(query, process) {
                console.log('query=' + query);
                process(['hoge', 'fuga', 'piyo']);
            }
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/f97d04d9-aef2-b882-cc0f-0d1448735148.jpeg)

```text:コンソール
query=o
```

- `source` に関数を指定できる。
- 第一引数に入力された文字列が渡される。
- 第二引数には関数が渡される。
    - この関数の引数に入力候補となる配列を渡して実行すると、オートコンプリートが表示される。
- Ajax を利用して入力候補を動的生成したいときなどに利用する。

#### `filter`：候補を絞りこまないようにする
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'autocomplete',
            source: ['hoge', 'fuga', 'piyo'],
            filter: false
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/b9581ecf-f678-086a-ff09-85405e501b73.jpeg)

- デフォルトでは、入力された値に合わせて候補が絞りこまれていく。
- `filter` に `false` を指定すると、絞り込みがされなくなる。

### `password`：パスワード
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'password'
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/0064dc72-f178-8653-062f-75b0d98de4e5.jpeg)

- 入力中の値、入力された値、が全てマスキングされる。

#### `hashLength`：表示を固定長にする
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'password',
            hashLength: 10
        }
    ]
});
```

![handsontable.gif](https://qiita-image-store.s3.amazonaws.com/0/28302/26f7ed75-f085-9594-ddc8-6d2ec3217e87.gif)

- 表示がマスクされていても桁数が分かると内容を推測される危険性がある。
- `hashLength` に桁数を指定すれば、入力の内容に関わらず常に指定したサイズのマスキングされた文字列が表示されるようになる。

#### `hashSymbol`：マスク文字を指定する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'password',
            hashSymbol: '@'
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/74cf73a7-df3d-10f8-d6d5-860dc5fb8deb.jpeg)

- `hashSymbol` でマスクに任意の文字を指定できる。

### `date`：日付
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'date'
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/005521fe-6c52-5501-a8c0-44e5afd87bb6.jpeg)

- `date` にすると日付入力になる。
- セルの編集を開始すると、カレンダーが表示される。
- デフォルトで不正な日付をチェックしてくれる。

#### `dateFormat`：日付書式を指定する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'date',
            dateFormat: 'YYYY-MM-DD'
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/d6b4c0ca-10e7-b365-8a08-8520a2847fd2.jpeg)

- `dateFormat` で日付書式を指定できる。
- 書式の指定方法は [Moment.js | Docs](http://momentjs.com/docs/#/parsing/string-format/) を参照。

#### `defaultDate`：初期値を指定する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'date',
            defaultDate: '01/01/2016'
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/ec287636-354f-82bc-899d-4f3e58f6ce0d.jpeg)

- `defaultDate` で編集を開始したときの初期日付を指定できる。

#### `datePickerConfig`：細かい動作を調整する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'date',
            datePickerConfig: {
                minDate: new Date()
            }
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/be81f3d6-90ca-9f8b-444d-6af82819fe46.jpeg)

- カレンダーの表示には、 [Pikaday](https://github.com/dbushell/Pikaday) というライブラリが使用されている。
- `datePickerConfig` で、この [Pikaday の設定](https://github.com/dbushell/Pikaday#configuration) を指定できる。
- 細かい調整は、この設定で行う。
- 例では、 `minDate` を使って選択できる最小の日付を指定している。

## `renderer`：セルの出力を制御する
### html をそのまま出力する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    data: [
        ['<u>underline</u>'],
        ['<a href="http://google.co.jp/">google</a>'],
        ['<button onclick="alert(\'hello\')">click</button>']
    ],
    columns: [
        {
            renderer: 'html'
        }
    ]
});
```

![handsontable.gif](https://qiita-image-store.s3.amazonaws.com/0/28302/9342054c-5ea0-5cff-0167-9e98f5ad884b.gif)

- `renderer` に `html` を指定すると、 HTML のタグがそのまま表示される。
- スクリプトも動くので、ユーザーが任意に入力できる場合はサニタイズが必要。

### サニタイズする
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    data: [
        ['<u>underline</u>'],
        ['<a href="http://google.co.jp/">google</a>'],
        ['<button onclick="alert(\'hello\')">click</button>']
    ],
    columns: [
        {
            renderer: function(instance, td, row, col, prop, value, cellProperties) {
                var escaped = Handsontable.helper.stringify(value);
                escaped = strip_tags(escaped, '<u><a>');
                td.innerHTML = escaped;
            }
        }
    ]
});

// original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
function strip_tags(input, allowed) {
    var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
        commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;

    // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
    allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join('');

    return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
        return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
    });
}
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/f7f519d2-6203-ca07-10cf-994375ead0fe.jpeg)

- [公式のユーザーガイド](http://docs.handsontable.com/0.23.0/demo-custom-renderers.html) に載ってた、頑張ってサニタイズする方法。

## `allowEmpty`：空入力を許可する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    data: [
        [
            'text', 'text', 'text',
            1, 2, 3,
            '2015/01/01', '2015/01/01', '2015/01/01',
            'foo', 'bar', 'foo'
        ]
    ],
    allowEmpty: false,
    columns: [
        {type: 'text'},
        {allowEmpty: true, type: 'text'},
        {allowEmpty: false, type: 'text'},
        {type: 'numeric'},
        {allowEmpty: true, type: 'numeric'},
        {allowEmpty: false, type: 'numeric'},
        {type: 'date'},
        {allowEmpty: true, type: 'date'},
        {allowEmpty: false, type: 'date'},
        {type: 'autocomplete', source: ['foo', 'bar']},
        {allowEmpty: true, type: 'autocomplete', source: ['foo', 'bar']},
        {allowEmpty: false, type: 'autocomplete', source: ['foo', 'bar']},
    ]
});
```

![handsontable.gif](https://qiita-image-store.s3.amazonaws.com/0/28302/b5a61473-8d40-f8e6-35cc-9ca9c75fdf00.gif)

- `true` を設定すると、空入力を許可する。
- `false` だと空入力するとエラーに（背景が赤く）なる。
- デフォルトは `true` なので、空入力可能。
- ただし、カラムの型によっては効かないっぽい。
- グリッド全体への指定と、個々のカラムへの指定の両方ができる。


## `readonly`：読み取り専用
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    data: [
        ['hoge', 'fuga']
    ],
    columns: [
        {
            readOnly: true
        },
        {
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/43034d30-5e05-d8b1-540f-4f9b9443887f.jpeg)

- `readOnly` を `true` にすると、そのカラムは読み取り専用になる。
- `O` は大文字。

## `allowInvalid`：不正な値の入力可否を制御する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            type: 'numeric',
            allowInvalid: false
        }
    ]
});
```

- `allowInvalid` に `false` を指定すると、不正な値は入力を確定できなくなる。
    - `type` に `numeric` を指定しているので、数値以外の文字を入力しようとしても、 `Enter` を押しても入力が確定できない。
- デフォルトは `true` なので、入力を確定することはできる。
    - しかし、不正な値が入力されている場合は、セルが赤色に着色される。

## `validator`：入力値を制限する
### 正規表現で指定する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            validator: /^[a-z]+$/
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/334c156c-2bac-3a80-076f-b725339621f4.jpeg)

- `validator` に正規表現（`RegExp` オブジェクト）を渡すと、その正規表現にマッチする値だけが入力OKになる。

### 関数で指定する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            validator: function(value, callback) {
                console.log(value);
                callback(value === 'hoge');
            }
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/940e82c0-2ac2-ec24-ce37-17892ed13c7c.jpeg)

- `validator` に関数を指定することもできる。
- 第一引数に、セルの値が渡される。
- 第二引数には関数が渡される。
    - この関数に `true` を渡せば検証OK、 `false` を渡せば検証NG扱いになる。


## `className`：CSSクラスを設定する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {className: 'foo'},
        {}
    ],
    cell: [
        {col: 1, row: 0, className: 'bar'}
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/edde53f8-cfe3-401b-0d97-af12a080f541.jpeg)

- `<td>` タグに任意の CSS クラスを設定できる。
- `columns` で指定すれば、その列の全ての `<td>` タグに CSS クラスが設定される。

## セルの編集をドロップダウンにする
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {
            editor: 'select',
            selectOptions: ['hoge', 'fuga', 'piyo']
        }
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/91e08e5f-9521-8027-ce51-3fbca07336a3.jpeg)

- `editor` に `select` を指定して、 `selectOptions` に選択肢を配列で渡す。


# セルを指定してオプションを設定する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    columns: [
        {type: 'numeric'}
    ],
    cell: [
        {col: 0, row: 2, type: 'date'}
    ]
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/72383282-7e46-1e81-1e9a-f7ad73f8ec64.jpeg)

- `cell` オプションを使うと、任意のセルを指定してオプションの上書きができる。

## 関数でセルのオプションを設定する
```js
var grid = document.getElementById('grid');

new Handsontable(grid, {
    cells: function(row, cols, prop) {
        return row % 2 === 0 ? {type: 'date'} : {type: 'numeric'};
    }
});
```

![handsontable.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/7d54da52-05e6-d0ab-f2fb-0d8f65c2b8c7.jpeg)

- `cells` オプションに関数を渡すと、セルごとの関数がコールバックされる。
- 関数が返したオブジェクトが、セルのオプションになる。




# 参考
- [Tutorial: Introduction | Handsontable - open source spreadsheet solution. Excel-like grid editing with HTML & JavaScript](http://docs.handsontable.com/0.24.0/tutorial-introduction.html)