(Wicket 6.4.0にて確認した現象)
ModalWindow表示前後、呼び出し元Pageクラスのインスタンスは異なる
ModalWindowが表示されている間、呼び出し側のPageクラスは直列化され、ModalWindowが閉じられるときに復元されるようです。
つまり、ModaoLWindow表示前後で呼び出し側Pageクラスの __ インスタンスは異なっています __ 。
これを意識せずにデータをやり取りするプログラムを書いてしまうとはまります。
検証コード
ModalWindowでリンクを押した時刻を呼び出し元に表示するプログラムで検証します。
NGコード
まずは呼び出し側のページのコード。
public class ParentPage extends WebPage {
private Date now = Calendar.getInstance().getTime();
private Label nowLabel;
public ParentPage() {
// 時刻を表示するラベル
this.nowLabel = new Label("now", new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
return DateFormat.getDateTimeInstance().format(now);
}
});
this.nowLabel.setOutputMarkupId(true);
this.add(this.nowLabel);
// ModalWindow
final ModalWindow modalWindow = new ModalWindow("modalWindow");
modalWindow.setPageCreator(new PageCreator() {
@Override
public Page createPage() {
final ChildPage.Callback callback = new ChildPage.Callback() {
@Override
public void callback(AjaxRequestTarget pTarget, Date pNow) {
// ModalWindowでリンクが押された時刻を記録してダイアログを閉じる
ParentPage.this.now = pNow;
modalWindow.close(pTarget);
}
};
return new ChildPage(callback);
}
});
modalWindow.setWindowClosedCallback(new WindowClosedCallback() {
@Override
public void onClose(AjaxRequestTarget pTarget) {
// ModalWindowが閉じられたタイミングで時刻ラベルを再描画
// (ブラウザ上の表記が更新されることを期待)
pTarget.add(nowLabel);
}
});
this.add(modalWindow);
// ModalWindowを表示するためのリンク
AjaxLink<?> shower = new AjaxLink<Object>("shower") {
@Override
public void onClick(AjaxRequestTarget pTarget) {
modalWindow.show(pTarget);
}
};
this.add(shower);
}
}
内部クラスが多く見づらいかもしれませんが、ポイントは以下の部分です。
public void callback(AjaxRequestTarget pTarget, Date pNow) {
// ModalWindowでリンクが押された時刻を記録してダイアログを閉じる
ParentPage.this.now = pNow;
modalWindow.close(pTarget);
}
特に違和感のないコードだと思います。
呼び出される側のページクラスは以下の通りです。
public class ChildPage extends WebPage {
public ChildPage(final Callback pCallback) {
AjaxLink<?> link = new AjaxLink<Object>("link") {
@Override
public void onClick(AjaxRequestTarget pTarget) {
// リンクが押されたことを現在時刻と共に呼び出し元に通知
pCallback.callback(pTarget, Calendar.getInstance().getTime());
}
};
this.add(link);
}
/**
* リンクが押されたことを通知するコールバック.
*/
public interface Callback extends Serializable {
void callback(AjaxRequestTarget pTarget, Date pNow);
}
}
しかし、このコードは期待どおりに動作しません。
時刻ラベルが更新されないのです。
解決版コード:PageReference
を使う
この問題を解決するには、PageReference
を使います。
先ほどのポイント部分のコードを以下のように書き換ると期待どおり動作するようになります。
public void callback(AjaxRequestTarget pTarget, Date pNow) {
// ModalWindowでリンクが押された時刻を記録してダイアログを閉じる
ParentPage p = (ParentPage) ParentPage.this.getPageReference().getPage();
p.now = pNow;
modalWindow.close(pTarget);
}
(ただし、ModalWindow表示中に呼び出し元ページを再描画しようとするとエラーになります。)
PageReference
ってなにもの?
PageReference
クラスは、このように、かなり重要なクラスのように思えるのですが、APIリファレンスは非常にあっさりしています。
もう少し親切だったらいいのになぁ。