Tabulatorにて、コンテキストメニューでの絞り込みを実装する

## 概要

Tabulator を用いた際に、絞り込みをもっと便利にしたいなぁと思い、
右クリックした際に、コンテキストメニュー出してそのセル値で楽に絞り込んでみました。

## Tabulator セットアップ

http://tabulator.info/docs/4.2/quickstart
公式のサンプルの通りにセットアップします。
とりあえず動かすだけなので、CDNから読み込みます。

```html
<head>
<meta charset="utf-8">
<link href="https://unpkg.com/tabulator-tables@4.2.4/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@4.2.4/dist/js/tabulator.min.js"></script>
</head>
<body>
<div id="example-table"></div>
<script>
 var tabledata = [
 	{id:1, name:"Oli Bob", age:"12", col:"red", dob:""},
 	{id:2, name:"Mary May", age:"1", col:"blue", dob:"14/05/1982"},
 	{id:3, name:"Christine Lobowski", age:"42", col:"green", dob:"22/05/1982"},
 	{id:4, name:"Brendon Philips", age:"125", col:"orange", dob:"01/08/1980"},
 	{id:5, name:"Margret Marmajuke", age:"16", col:"yellow", dob:"31/01/1999"},
 ];

var table = new Tabulator("#example-table", {
 	height:205, // set height of table (in CSS or here), this enables the Virtual DOM and improves render speed dramatically (can be any valid css height value)
 	data:tabledata, //assign data to table
 	layout:"fitColumns", //fit columns to width of table (optional)
 	columns:[ //Define Table Columns
	 	{title:"Name", field:"name", width:150},
	 	{title:"Age", field:"age", align:"left", formatter:"progress"},
	 	{title:"Favourite Color", field:"col"},
	 	{title:"Date Of Birth", field:"dob", sorter:"date", align:"center"},
 	]
});
</script>
</body>
```
## tabulator 実行画面

![スクリーンショット 2019-04-13 15.13.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136889/20e3f3e7-d4a0-c931-3354-d8f0a9e4733c.png)

## 右クリックイベントを検知させる

> http://tabulator.info/docs/4.2/callbacks#cell
> 
> Cell Right Click
> The cellContext callback is triggered when a user right clicks on a cell, it can be set on a per column basis using the option in the columns definition object.
> 
> ```js
> {title:"Name", field:"name", cellContext:function(e, cell){
>     //e - the click event object
>     //cell - cell component
>     },
> }
> ```

とありますので、これを使います。

```js
cellContext: function(event, cell){
    //event - the click event object
    //cell - cell component
    // 通常の右クリックメニューを停止
    event.preventDefault();
    // 代わりに自作のメニューを表示
    showContextMenu(cell.getField(),cell.getValue(), event.pageX, event.pageY );
},
```

自作コンテキストメニューを表示させるため、自前の`showContextMenu`関数を加えます。
関数内で、リストを作成し、そこに現在クリックしたセルの値とともに、そのリストをクリックした際にイベントを発火し、絞り込みを実行させます。

```js
var showContextMenu = function(field, value, posx , posy) {
    var cm = document.getElementById("contextmenu");

    // 非表示をやめて、クリックした位置に表示する
    cm.style.left = posx + 'px';
    cm.style.top = posy + 'px';
    cm.style.display = '';

    var li = document.createElement('li');
    li.innerText = value + 'で絞り込む';
    // クリックイベント時に、headerfilterを実施する
    li.addEventListener('click', function(){ setHeaderFilter(field, value) });

    var ul = cm.getElementsByTagName('ul');
    // リストの中身を空にして追加
    ul[0].innerHTML = '';
    ul[0].appendChild(li);
} ;
```

自作コンテキストメニューのためのCSSとHTML

```html
<style>
.contextmenu-wrapper{
  position: absolute;
}
.contextmenu-contents{
  position: relative;
  border: 2px solid #CCC;
  background-color: #FFF;
  box-shadow: 0 .5rem 1rem rgba(0,0,0,.15);
  padding: .25em;
}
.contextmenu-contents ul {
  list-style: none;
  margin: .25em;
  padding: 0;
}

.contextmenu-contents li:hover {
  background-color:#AAF;
  cursor: pointer;
}
</style>
```

```html
<div id="example-table"></div>
<div id="contextmenu" class="contextmenu-wrapper" style="display: none;">
  <div class="contextmenu-contents">
    <ul></ul>
  </div>
</div>
```

## コンテキストメニュー実装画面

![スクリーンショット 2019-04-13 16.27.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136889/87ba586a-69e5-6419-3ca7-fecc86223eb5.png)

## HeaderFilterの準備

tabulator設定時の columnsに `headerFilter: true` を加えます。
※ 公式に`Note: At present, the progress and star editors are not available as header filters.` とある通り、プログレスおよびスター表示の内容には、ヘッダーフィルターは使えません。

```js
columns:[ //Define Table Columns
    {title:"Name", field:"name", width:150, headerFilter: true},
    {title:"Age", field:"age", align:"left", formatter:"progress"},
    {title:"Favourite Color", field:"col", headerFilter: true},
    {title:"Date Of Birth", field:"dob", sorter:"date", align:"center", headerFilter: true},
],
```

## ヘッダーフィルターへ値を適用する関数

tabulatorに用意されている`setHeaderFilterValue`関数に、フィールド名と値を渡す関数を作ります。
クリック後は、不要となるのでコンテンツメニューを隠します。

```js
var setHeaderFilter = function (cell, value) {
    this.table.setHeaderFilterValue(cell, value);
    hideContextMenu();
}
var hideContextMenu = function() {
    var cm = document.getElementById("contextmenu");
    cm.style.display = 'none';
} ;
```

## 完成

codepenに貼り付けました。

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="majirou" data-slug-hash="KYvXmV" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="KYvXmV">
  <span>See the Pen <a href="https://codepen.io/majirou/pen/KYvXmV/">
  KYvXmV</a> by majirou (<a href="https://codepen.io/majirou">@majirou</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>