w2uiを使ってみる

無償で、編集可能なgridを使える[w2ui](http://w2ui.com/web/home)を試してみます。

##1.ダウンロードとインストール
- ダウンロード
[GitHUB](https://github.com/vitmalina/w2ui)からダウンロードできます。

- インストール
JQueryベースなので、JQueryと, w2ui.min.css, w2ui.min.jsを使います。

``` サンプル.html
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta charset="utf-8">
    <title></title>
    <meta name="description" content="">
    <meta name="author" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="">
    <link rel="shortcut icon" href="">

    <title>W2UI Demo: combo-2</title>
    <script src="libs/jquery/jquery-3.2.1.min.js"></script>
    <script type="text/javascript" src="dist/w2ui.min.js"></script>
    <link rel="stylesheet" type="text/css" href="dist/w2ui.min.css" />
</head>
<body>
</body>
</html>
```

##2.フォーム

W2uiで画面を作成すると、下記のようになる。フォームにJSONデータをバインドできる。ただ、フォームに入力しても、JSONデータには反映されない。入力したデータを取得する場合には、「w2ui["myForm"].record」を取得する必要がある。

```login.html
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta charset="utf-8">
    <title></title>
    <meta name="description" content="">
    <meta name="author" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="">
    <link rel="shortcut icon" href="">

    <title>W2UI Form (ログイン画面)</title>
    <script src="libs/jquery/jquery-3.2.1.min.js"></script>
    <script type="text/javascript" src="dist/w2ui.min.js"></script>
    <link rel="stylesheet" type="text/css" href="dist/w2ui.min.css" />
</head>
<body>
  <div id="myForm" style="width: 400px"></div>

  <script>

    var data = { userid: 'user01', password: null }

    $(function () {
        $('#myForm').w2form({ 
            name   : 'myForm',
            header   : 'ログイン認証',
            fields : [
                { field: 'userid', name: 'ユーザＩＤ', type: 'text', required: true },
                { field: 'password', name: 'パスワード',  type: 'password', required: true },
            ],
            record : data,
            actions: {
                ログイン: function () {
                    console.log(JSON.stringify(w2ui["myForm"].record));
                }
            }
        });s
    });
  </script>
</body>
</html>
```

表示してみると以下のような感じになる。
<img src="https://qiita-image-store.s3.amazonaws.com/0/246741/e555e979-dbc2-b288-af84-4017b6228c60.png" width=50%>

##3.Grid

###(1)基本的な使い方

Gridもあり、使い方の簡単です。以下のソースで、フィルタやフッタまで表示される。

```grid1.html
<!DOCTYPE html>
<html>
<head>
    <title>W2UI Grid</title>
    <script src="libs/jquery/jquery-3.2.1.min.js"></script>
    <script type="text/javascript" src="dist/w2ui.min.js"></script>
    <link rel="stylesheet" type="text/css" href="dist/w2ui.min.css" />
</head>
<body>

<div id="grid" style="width: 100%; height: 350px;"></div>

<script type="text/javascript">
$(function () {
    $('#grid').w2grid({ 
        name: 'grid', 
        show : {
            toolbar        : true,
            footer         : true,
            lineNumbers    : true,
        },
        columns: [                
            { field: 'recid', caption: 'ID', size: '50px', sortable: true },
            { field: 'fname', caption: 'First Name', size: '30%', sortable: true },
            { field: 'lname', caption: 'Last Name', size: '30%', sortable: true },
            { field: 'email', caption: 'Email', size: '40%' },
            { field: 'sdate', caption: 'Start Date', size: '120px' }
        ],
        records: [
            { recid: 1, fname: 'John', lname: 'doe', email: 'jdoe@gmail.com', sdate: '4/3/2012' },
            { recid: 2, fname: 'Stuart', lname: 'Motzart', email: 'jdoe@gmail.com', sdate: '4/3/2012' },
            { recid: 3, fname: 'Jin', lname: 'Franson', email: 'jdoe@gmail.com', sdate: '4/3/2012' },
            { recid: 4, fname: 'Susan', lname: 'Ottie', email: 'jdoe@gmail.com', sdate: '4/3/2012' },
            { recid: 5, fname: 'Kelly', lname: 'Silver', email: 'jdoe@gmail.com', sdate: '4/3/2012' },
            { recid: 6, fname: 'Francis', lname: 'Gatos', email: 'jdoe@gmail.com', sdate: '4/3/2012' },
            { recid: 7, fname: 'Mark', lname: 'Welldo', email: 'jdoe@gmail.com', sdate: '4/3/2012' },
            { recid: 8, fname: 'Thomas', lname: 'Bahh', email: 'jdoe@gmail.com', sdate: '4/3/2012' },
            { recid: 9, fname: 'Sergei', lname: 'Rachmaninov', email: 'jdoe@gmail.com', sdate: '4/3/2012' },
        ]
    });    
});
</script>
</body>
</html>
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/cce6501e-03e6-ecba-3c71-8646c434ec07.png)


###(2)Inline Editing

Inline Editingが簡単に実装できます。
columnsプロパティに、「editable」プロパティを追加して使います。

```editable.js

columns: [   
  { field: 'text', caption: 'text', editable: { type: 'text' } },
  { field: 'text', caption: 'text', editable: { type: 'int' } },
  { field: 'select', caption: 'select', editable: { type: 'select', items: itemlist } },
]
```

#### typeの主な種類は以下の表のとおり。

|type|指定する代表的なオプション|
|:-------|:------|
|text |
|int| min: 0, max: 32756 |
|float| precision: 1 | 
|money ||
|select| items: itemlist | 
|checkbox| 
|date | format: "yyyy/mm/dd" 
|time | 
|list| items: itemlist, showAll: true |
|combo| items: itemlist, filter: false | 
|percent| precision: 1 | 
|color |

#### int, float, money, percent

数値以外は入力できないようになっている。precisionは小数点の桁数。

#### select

selectやlistは、プルダウンに表示するリストを指定する。

```itemlist.js
var itemlist =["item1","item2"]
```

JSONでも指定できる。

```itemlist2.js
var itemlist =[{id:1, text:"item1"},{id:2, text:"item2"}]
```

#### date, time

dateを指定すると、カレンダーが表示される。timeは時間と分を選択するポップアップが表示される。
<img src="https://qiita-image-store.s3.amazonaws.com/0/246741/6c2446d4-d202-0839-458d-24da5f64d480.png" width=80%>


#### list, combo

list, comboは、filter機能がある。filterは、文字列を含む場合は、match: 'contains'とする。検索対象となるitemsの配列数が多い場合は、cacheMaxを指定しないと検索対象にならないので注意する。

```list.js
{ field: 'list', caption: 'list', size: '50%', 
 editable: { type: 'list', items: addresslist, filter: true, match: 'contains',cacheMax: 5000 },
},
```

#### サンプルhtml

```grid2.html
<!DOCTYPE html>
<html>
<head>
    <title>W2UI Grid</title>
    <meta charset="windows-31j">
    <script src="libs/jquery/jquery-3.2.1.min.js"></script>
    <script type="text/javascript" src="dist/w2ui.min.js"></script>
    <link rel="stylesheet" type="text/css" href="dist/w2ui.min.css" />
</head>
<body>
<div class="content">
    <div id="example_view"></div>
</div>

<!--CODE-->
<div id="grid" style="width: 100%; height: 300px;"></div>
<br>
<button class="w2ui-btn" onclick="showData()">データ表示</button>

<!--CODE-->
<script>
  var itemlist =[
    {id:1, text:"item1"},
    {id:2, text:"item2"},
    {id:3, text:"item3"},
    {id:4, text:"item4"},
    {id:5, text:"item5"},
  ]

$(function () {
    $('#grid').w2grid({ 
        name: 'grid',
        selectType: 'cell',
        columns: [                
            { field: 'recid', caption: 'ID', size: '50px' },
            { field: 'text', caption: 'text', size: '120px', 
                editable: { type: 'text' }
            },
            { field: 'int', caption: 'int', size: '80px', render: 'int', 
                editable: { type: 'int', min: 0, max: 999 }
            },
            { field: 'float', caption: 'float', size: '80px', render: 'float:1', 
                editable: { type: 'float', precision: 1 } 
            },
            { field: 'money', caption: 'money', size: '80px', render: 'money',
                editable: { type: 'money' }
            },
            { field: 'percent', caption: 'percent', size: '80px', render: 'percent:1', 
                editable: { type: 'percent', precision: 1 } 
            },
            { field: 'color', caption: 'color', size: '80px', 
                editable: { type: 'color' }
            },
            { field: 'date', caption: 'date', size: '90px', style: 'text-align: right',
                editable: { type: 'date', format:'yyyy/mm/dd' } 
            },
            { field: 'time', caption: 'time', size: '70px', 
                editable: { type: 'time' } 
            },
            { field: 'list', caption: 'list', size: '50%', 
                editable: { type: 'list', items: itemlist, filter: true, match : 'contains',cacheMax: 5000 },
                render: function (record, index, col_index) {
                    var html = this.getCellValue(index, col_index);
                    return html || '';
                }
            },
            { field: 'combo', caption: 'combo', size: '50%', 
                editable: { type: 'combo', items: itemlist, filter: true, match : 'contains',cacheMax: 5000 } 
            },
            { field: 'select', caption: 'select', size: '100px', 
                editable: { type: 'select', items: [{ id: '', text: '' }].concat(itemlist) }, 
                render: function (record, index, col_index) {
                    var html = '';
                    for (var p in itemlist) {
                        if (itemlist[p].id == this.getCellValue(index, col_index)) html = itemlist[p].text;
                    }
                    return html;
                }
            },
            { field: 'check', caption: 'check', size: '60px', style: 'text-align: center',
                editable: { type: 'checkbox', style: 'text-align: center' } 
            }
        ],
        records: [
            { recid: 1, int: 100,float: 1.1, money: 100, percent: 55, date: '2014/1/1', combo: 'item1', check: true },
            { recid: 2, int: 200,float: 21.1, money: 454.40, percent: 15, date: '2014/1/1', combo: 'item1', check: false, list: { id: 1, text: 'item1' } },
            { recid: 3, int: 350,float: 31.1, money: 1040, percent: 98, date: '2014/1/1', combo: 'item1', check: true },
            { recid: 4, int: 350,float: 41.1, money: 140, percent: 58, date: '2014/1/1', combo: 'item1', check: true, list: { id: 3, text: 'item3' } },
            { recid: 5, int: 350,float: 51.1, money: 500, percent: 78, date: '2014/1/1', check: false },
            { recid: 6, text: 'some text', int: 350, money: 440, percent: 59, date: '2014/1/1', check: false },
            { recid: 7, int: 350, money: 790, percent: 39, date: '2014/1/1', check: false },
            { recid: 8, int: 350, money: 4040, percent: 12, date: '2014/1/1', check: true, list: { id: 5, text: 'item5' } },
            { recid: 9, int: 1000, money: 3400, percent: 100, date: '2014/1/1' }
        ]
    });    
});

function showData() {
    w2alert(JSON.stringify(w2ui['grid'].records)); 
}
</script>
</body>
</html>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/246741/96d4da83-6b9c-1afd-a5ef-e7869faa21b7.png)


※editorは、formでも同様に使えます。

※ 2019.05.26 追記
w2uiの datetime型ではまったのでメモとして追記しておきます。

W2ui frameworkにおいて、 gridとformで記述が少し違います。

### datetime, date
#### grid

gridは render属性を設定する。

```
render: 'date:yyyy-mm-dd'
```

```
render: 'datetime:yyyy-mm-dd|hh24:mm:ss'
```

記述例：

```grid.html
<body>
<h3>show users with w2ui grid</h3>
<link rel="stylesheet" type="text/css" href="/static/lib/css/w2ui.min.css" media="all"/>
<script type="text/javascript" src="/static/lib/js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="/static/lib/js/w2ui.min.js"></script>
<div id="grid" style="width: 100%; height: 350px;"></div>
<script type="text/javascript">
$(function () {
    $('#grid').w2grid({ 
        name: 'grid', 
        recid: 'id',
        columns: [                
            { field: 'id',  caption: 'id', size: '50px', sortable: true },
            { field: 'username', caption: 'username', size: '10%', sortable: true },
            { field: 'mailaddress', caption: 'mailaddress', size: '10%', sortable: true },
            { field: 'password', caption: 'password', size: '10%', sortable: true,
              render:'password' 
            },
            { field: 'role', caption: 'role', size: '50px', sortable: true,
              render: function(record){
                return {0: 'admin', 7: 'user', 9: 'guest'}[record.role]
              },
            },
            { field: 'birthday', caption: 'birthday', size: '10%', sortable: true,
              render: 'date:yyyy-mm-dd'
            },
            { field: 'created_at', caption: 'created_at', size: '10%', sortable: true,
              render: 'datetime:yyyy-mm-dd|hh24:mm:ss'
            },
            { field: 'updated_at', caption: 'updated_at', size: '10%', sortable: true,
              render: 'datetime:yyyy-mm-dd|hh24:mm:ss'
            },
        ],
        records: {{ list|safe }},
    });    
});
</script>
</body>
```

#### form

formは option属性に、さらにformat属性を設定する。

```
type: 'date', options: {format: 'yyyy-mm-dd'}, 
```

```
type: 'datetime', options: {format: 'yyyy-mm-dd|hh24:mm:ss'}, 
```

記述例：

```form.html
<body>
<h3>show user with w2ui form (auto template)</h3>
<link rel="stylesheet" type="text/css" href="/static/lib/css/w2ui.min.css" media="all"/>
<script type="text/javascript" src="/static/lib/js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="/static/lib/js/w2ui.min.js"></script>

<div id="form" style="width: 600px;"></div>

<script>
$(function () {
    $('#form').w2form({
        name   : 'form',
        recid: 'id',
        fields : [
            { field: 'id', type: 'text', 
                html: { caption: 'id', attr: 'tabindex="-1" readonly style="background: transparent;' } 
            },
            { field: 'username', type: 'text', required: true, 
                html: { caption: 'username', attr: '' } 
            },
            { field: 'mailaddress', type: 'text', 
                html: { caption: 'mailaddress', attr: '' } 
            },
            { field: 'password', type: 'password', required: true, 
                html: { caption: 'password', attr: '' } 
            },
            { field: 'role', type: 'select', required: true, 
                options: {
                    items:[
                        {id:0, text:'admin'} , 
                        {id:7, text:'user'} , 
                        {id:9, text:'guest'} , 
                    ],
                },
                html: { caption: 'role', attr: '' } 
            },
            { field: 'birthday', type: 'date',
                options: {
                    format: 'yyyy-mm-dd'
                }, 
                html: { caption: 'birthday'},
            },
            { field: 'created_at', type: 'datetime',
                options: {
                    format: 'yyyy-mm-dd|hh24:mm'
                }, 
                html: { caption: 'created_at'},
            },
            { field: 'updated_at', type: 'datetime',
                options: {
                    format: 'yyyy-mm-dd|hh24:mm'
                }, 
                html: { caption: 'updated_at'},
            },
        ],
        record: {{ data|safe }},
        actions: {
            'Save': function (event) {
                console.log('save', event);
                // this.save();
            },
            'Clear': function (event) {
                console.log('clear', event);
                // this.clear();
            }
        }
    });
});
</script>
</body>
```

##4.その他

その他にも、layoutやpopupなどのUIがたくさん揃っています。記事では書ききれないので公式サイトを見てください。

##5.終わりに

Djangoなどのtemplate機能でも簡単に実装できますが、複雑なフォームを作成しようと思ったらjavascriptなどでたくさんのコードを記述しないといけないんですが、W2UIを使うと、１対多のモデルでもかなり少ないコードで実装できそうです。