チェックBOXが存在するリストの表示&制御は、業務系Webの開発でよくあるもので、
案件の都度、相当量の JavaScript とサーバサイドを作らなくてはならなくあまり汎用的なモデルが存在しない。
とは言え、やはり少しでも使いそうなパターンはモデルとして残しておきたいということで。。。
チェックをONしたものだけを、refresh ボタンで、残すというリストの例です。
今回の Wicket のプログラムは、checkbox の状態保持として PropeertyModel を使用するのが、ミソなのですが、
注意が必要なのは、全てのチェックBOXのON/OFFを制御する時、AjaxCheckBoxの behavior で JavaScriptを実行しますが、
jQuery の prop で、checkbox の true/false をセットするだけは、チェックBOXの changeイベントが走りません。
そこで、prop で真偽を逆にセットして、trigger で click を実行することで、changeイベントを走らせて、WicletのListView populateItem の中で
設定する checkbox の change イベント捕捉処理を実行させるのです。
public class RefreshListPage extends WebPage{
public List<Cell> mlist;
protected Map<Integer, Cell> checkedMap;
protected List<String> checkWicketIdlist;
public RefreshListPage(){
// リスト初期化
initList();
Form<Void> form = new Form<Void>("form");
final WebMarkupContainer listContainer = new WebMarkupContainer("listContainer");
listContainer.setOutputMarkupId(true);
final ListView<Cell> listview = new ListView<Cell>("listview", new PropertyModel<List<Cell>>(this, "mlist")){
@Override
protected void populateItem(final ListItem<Cell> item){
final Cell cell = item.getModelObject();
AjaxCheckBox checkBox = new AjaxCheckBox("check", new Model<Boolean>(cell.isSelected)){
@Override
protected void onUpdate(AjaxRequestTarget target){
// 選択なら Map に格納、未選択なら Mapから削除
cell.isSelected = getModelObject();
if (getModelObject()){
checkedMap.put(cell.id, cell);
}else{
checkedMap.remove(cell.id);
}
}
};
checkWicketIdlist.add(checkBox.getMarkupId());
item.add(checkBox);
item.add(new Label("number", cell.id));
// checkbox ON/OFF → 行背景色をセット
item.add(new AttributeModifier("style", new AbstractReadOnlyModel<String>(){
@Override
public String getObject(){
return item.getModelObject().isSelected ? "background-color: #f0ffeb" : "background-color: #ffffff";
}
}));
}
// ListView の表示タイミング checkbox 変化で行背景色を変化させる jQuery を実行する。
@Override
protected void onAfterRender() {
super.onAfterRender();
/* このページ用のJavaScript、RefreshListPage.js で定義したメソッドを実行する */
JavaScriptUtils.writeJavaScript(getResponse(), "rowcolorChangeSetting();");
}
};
listContainer.add(listview);
form.add(listContainer);
// All checkbox ・・・逆の真偽 !getModelObject() をセットして click tigger 実行する。
form.add(new AjaxCheckBox("allCheck", new Model<Boolean>(false)){
@Override
protected void onUpdate(AjaxRequestTarget target){
String value = Boolean.toString(!getModelObject());
for(String idstr:checkWicketIdlist){
target.appendJavaScript("$('#" + idstr + "').prop('checked'," + value + ").trigger('click');");
}
}
});
// Refresh
form.add(new AjaxLink<Void>("refresh"){
@Override
public void onClick(AjaxRequestTarget target){
// リスト mlist を一度全てクリア
mlist.clear();
checkWicketIdlist.clear();
// check されたものだけを mlist に追加
for(Integer key:checkedMap.keySet()){
mlist.add(checkedMap.get(key));
}
target.add(listContainer);
}
});
// Add
form.add(new AjaxLink<Void>("add"){
@Override
public void onClick(AjaxRequestTarget target){
// TODO リスト mlist に、追加 を行う。
checkWicketIdlist.clear();
target.add(listContainer);
}
});
// submit
form.add(new AjaxButton("submit", form){
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> f){
for(Integer id:checkedMap.keySet()){
// チェックされた分を認識
}
}
});
//
add(form);
}
/* リスト初期化 */
private void initList(){
checkedMap = new HashMap<Integer, Cell>();
mlist = new ArrayList<Cell>();
// TODO リスト mlist 初期表示時に必要なだけ格納する。
checkWicketIdlist = new ArrayList<String>();
}
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(CssHeaderItem.forReference(new CssResourceReference(RefreshListPage.class, "RefreshListPage.css")));
response.render(JavaScriptHeaderItem.forReference(new JavaScriptResourceReference(RefreshListPage.class, "jquery-2.1.1.min.js")));
response.render(JavaScriptHeaderItem.forReference(new JavaScriptResourceReference(RefreshListPage.class, "RefreshListPage.js")));
}
}
----------------------------
css を書いた RefreshListPage.css は、以下のとおり。
@CHARSET "UTF-8";
table.grid{
border-spacing: 0; border-collapse: collapse;
box-sizing: border-box;
display: inline-block;
border: 1px #e3e3e3 solid;
}
.grid tbody{
box-sizing: border-box;
height: 200px;
display: inline-block;
overflow-y: scroll;
}
.grid th{ background-color: #c0d0d0; }
.grid th, .grid td{
border: 1px solid #888888;
padding: 5px 10px;
box-sizing: border-box;
}
.grid th:nth-child(1){ width: 70px; }
.grid th:nth-child(2){ width: 200px; }
.grid td:nth-child(1){ width: 70px; text-align: center; }
.grid td:nth-child(2){ width: 200px; }
---------------------------------------------
HTMLは以下のとおり。
<wicket:extend>
<form wicket:id="form">
<div>
<table class="grid">
<thead>
<tr>
<th><input type="checkbox" wicket:id="allCheck"></th>
<th>ID</th>
</tr>
</thead>
<tbody wicket:id="listContainer">
<tr wicket:id="listview">
<td><input type="checkbox" wicket:id="check"></td>
<td wicket:id="number"></td>
</tr>
</tbody>
</table>
</div>
<br/>
<div>
<table style="white-space: nowrap;">
<tr>
<td><a href="#" wicket:id="refresh"><button type="button">refresh</button></a></td>
<td width="100"></td>
<td><a href="#" wicket:id="add"><button type="button">add</button></a></td>
<td width="100"></td>
<td><button type="submit" wicket:id="submit">submit</button></td>
</tr>
</table>
</div>
</form>
</wicket:extend>
---------------------------------------------
RefreshListPage.jsは以下のとおり。
/* checkbox ON で、行背景色変更を設定する。*/
var rowcolorChangeSetting = function(){
$("input[type='checkbox']").change(function(){
$(this).parent().parent().css("background-color", $(this).prop("checked") ? "#f0ffeb" : "#ffffff");
});
};
$(function(){
 rowcolorChangeSetting();
});