Webページ上で、編集可能な表といえば、
Handsontable | JavaScript Data Grid Component For Web Apps
や、
http://tabulator.info/
が、有名なので、このどちらかを提案することが多いのだが、
Wicket は、これより昔から、DataView 使用と Form 入力フィールドの混合での構成で
Wicket-stuff から、Editable Grid が提供されてる。
Wicket の最新 latest バージョン 8.4.0 に対応して Wicket-Stuff も 8.4.0 で出してはいる。
Wicket-stuff のGit-Hub からサンプルソースを入手して動かしてみると
CSSスタイルは、何もなく原始的な table のままで、後から記述しないとならない。
Handsontable や Tabulator 等、メジャーで普及しているのは、機能も豊富で賛同するところもあり、
右クリックコンテキストメニューによる操作がフレームワークとして提供されているのは嬉しいが、
右クリックコンテキストメニューの存在を、エンドユーザに説明する必要があって
本当にBest なのか?いつも疑問が残る。
Editable Grid · wicketstuff/core Wiki · GitHub
Wicket-stuff の Editable Grid を サンプルをそのまま動かすと、、、
編集操作は全て、単純なリンクである。
見た目が簡素であるが、右クリックコンテキストメニューを採用しない代わりに
一目で操作方法は掌握できる。
これを、fontawesome や、Bootsrtap を使ってもう少し見栄えを良くしていく。
Wicket ページ HTML に、
<wicket:head> <link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.5.0/css/all.min.css" rel="stylesheet"> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script> </wicket:head>
を記述する。
グリッドコンテンツのページ HTML は、
<div class="container"> <div wicket:id="grid" id="grid"></div> <div style="margin-top:20px"> <button wicket:id="submit" type="button" class="btn btn-primary">submit</button> </div> </div>
今回、FeedbackPanel は使用せずに除去してある。
CSSは、
@charset "UTF-8"; #grid .navigator a{ font-size: 1rem; margin: 1px 10px; } #grid .navigator span.goto a[disabled='disabled']{ color: #ff00ff !important; } #grid .headers th{ background-color: #cccccc; } #grid tbody tr:nth-child(even){ background-color: #cce7ff; } #grid tbody tr td:last-child div div a{ margin: 0 0.5rem; color: #aaaaaa; } #grid th, #grid td{ white-space: nowrap; }
リンク → アイコン にする JavaScript
/** * custom-grid.js */ var renderCount = function(){ var navigationlabel = $('.navigatorLabel div').html(); if (navigationlabel==undefined){ $('#grid thead').prepend('<tr class="navigation"><td colspan="4"><div class="navigatorLabel">Total : ' + $('#grid tbody tr').length + '</div></td></tr>') }else{ $('.navigatorLabel div').html('Total : ' + navigationlabel.split(/ /)[5]); } }; var setActionCell = function(){ $('#grid a[id^="edit"]').html('<i class="fa fa-edit" title="編集"></i>'); $('#grid a[id^="save"]').html('<i class="fa fa-save" title="保存"></i>'); $('#grid a[id^="cancel"]').html('<i class="fa fa-undo" title="キャンセル"></i>'); $('#grid a[id^="delete"]').html('<i class="fa fa-trash-alt" title="削除"></i>'); $('#grid a[id^="add"]').html('<button type="button" class="btn btn-secondary">追加</button>'); setEdlitAction(); }; var setEdlitAction = function(){ $('#grid a[id^="edit"]').click(function(e){ setTimeout('setActionCell();', 100); }); };
ページ表示は、こんな感じ、、、
編集のアイコンをクリックした時、クリックした行は入力フィールドになる。
ページの Javaソースは、、
EditableGrid 設置のカスタマイズ
onDelete, onSave, onAdd で、対象リストを操作は不要!である。
onError は、Validatorによる入力エラー検知→FeedbackPanel 設置してなければ Override 意味がない。
queue(new EditableGrid<Person, String>("grid", getColumnProperty() , new EditableListDataProvider<Person, String>(personlist), 5, Person.class){ @Override protected void onError(AjaxRequestTarget target){ // target.add(feedbackPanel); } @Override protected void onCancel(AjaxRequestTarget target){ target.appendJavaScript("setActionCell();"); } @Override protected void onDelete(AjaxRequestTarget target, IModel<Person> rowModel){ target.appendJavaScript("renderCount();setActionCell();"); // 削除の Person → rowModel.getObject(); } @Override protected void onSave(AjaxRequestTarget target, IModel<Person> rowModel){ target.appendJavaScript("setActionCell();"); // 更新の Person → rowModel.getObject(); } @Override protected void onAdd(AjaxRequestTarget target, Person newRow){ target.appendJavaScript("renderCount();setActionCell();"); // 削除の Person → newRow } @Override protected void onAfterRender(){ super.onAfterRender(); // style 適用のJS実行 JavaScriptUtils.writeJavaScript(getResponse(), "renderCount();setActionCell();"); } }); queue(new Button("submit").add(AjaxEventBehavior.onEvent("click", t->{ personlist.stream().forEach(e->{ logger.debug("■ id="+e.id+" "+e.name+" "+e.address+" "+e.age); }); t.appendJavaScript("alert('submit');"); })));
EditableGrid コンストラクタで指定する行追加及び編集の入力フィールド Component 設置するための
List<AbstractEditablePropertyColumn> を取得するメソッド
FeedbackPanel 設置しないので RequiredEditableTextFieldColumn を使わずに
EditableTextFieldPropertyColumn 等を使用する。
private List<AbstractEditablePropertyColumn<Person, String>> getColumnProperty(){ List<AbstractEditablePropertyColumn<Person, String>> columns = new ArrayList<AbstractEditablePropertyColumn<Person, String>>(); columns.add(new EditableTextFieldPropertyColumn<Person, String>(new Model<String>("Name"), "name")); columns.add(new EditableTextFieldPropertyColumn<Person, String>(new Model<String>("Address"), "address")); columns.add(new AbstractEditablePropertyColumn<Person, String>(new Model<String>("Age"), "age"){ @SuppressWarnings("rawtypes") @Override public EditableCellPanel getEditableCellPanel(String componentId){ EditableRequiredDropDownCellPanel<Person, String> panel = new EditableRequiredDropDownCellPanel<Person, String>(componentId, this , Arrays.asList("10", "11", "12", "13", "14", "15")); ((DropDownChoice)panel.get("dropdown")).setNullValid(true); return panel; } }); return columns; }
EditableListDataProvider で指定する List<Person> personlist は、
EditableGrid を queue する前に生成しておく。
age の選択、DropDownChoice が、未選択=「選んでください。」でなく空白にしたいので、
EditableRequiredDropDownCellPanel でセットする DropDownChoice を
setNullValid(true) にする。
Maven pom.xml の記述は、、
<dependency> <groupId>org.wicketstuff</groupId> <artifactId>wicketstuff-editable-grid</artifactId> <version>8.4.0</version> </dependency>
Wicket-stuff の Editable Grid のメリットは、、
行の編集、更新、追加、削除、→ 対象がDBだった場合に、
EditableListDataProvider の onメソッドで、
リアルタイムに1レコードずつの操作→反映が、簡単に記述構成できる点である。
Handsontable や、Tabulator では、アクションに対するAJAX通信を大量に書かなくては
ならないはずで、入力エラーも考慮するとかなり面倒くさい。。