2008年08月19日

10章(Using Javascript)レビュー

WicketはWebアプリケーションを、Swingアプリのように作れるわけですが、そうは言っても作ったあとの動作はやっぱりWebアプリケーションなわけです。Ajaxコンポーネントを使うことで、Webっぽくない動作をすることもできますが、Javascriptを使ったクライアントサイドのロジックも必要です。一番単純な例では、削除ボタンを押したときに「削除してもよろしいですか?はい・いいえ」みたいな確認ダイアログです。これぐらいならばJavascriptで即時に確認したほうがいいです。

この章では、WicketコンポーネントでJavascriptを使う方法を書いています。「全部サーバーサイドでやれ」っていうような閉鎖的なものではなく、このような拡張性も柔軟にできるようになっています。

まずは、Wicket抜きで、HTML+Javascriptだけで解決する方法。submitボタンのonclick属性に記述したスクリプトの戻り値がfalseであれば、submitしないので確認ダイアログに使用できます。

ただ、確認ダイアログを表示するボタンを配置するたびに、Javascriptを記述するのは面倒なので、確認ダイアログ付ボタン的なコンポーネントを作ります。
Panelを継承して、htmlとJavaコンポーネントを作成します。htmlは2つの部分に分けられます。
1つは、<wicket:head>で囲まれるヘッダー部。もう1つはPanelコンポーネントのレンダリングに使用される<wicket:panel>で囲まれる部分です。このコンポーネントが配置されると、htmlのヘッダー部に、<wicket:head>ないの記述がレンダリングされます。
したがって、ヘッダー部にJavascriptを記述して、パネル部にSubmitボタンの記述をすることで、確認ダイアログ付ボタン的なコンポーネント(=ConfirmDelete)コンポーネントを作成することができます。

Chapter10 Using Javascriptからの引用
<wicket:head>
<script type="text/javascript">
function getConfirmation(){
  return confirm("削除してもOK?");
}
</wicket:head>

<wicket:panel>
<input type="submit" value="Delete" onclick="return getConfirmation()" />
</wicket:panel>

このようにコンポーネント化するだけで、htmlのほうはすっきりしました。デザイン的に影響のあるようなコンポーネント化ではないため、このようなコンポーネント化はどんどん進めるべきだと思います。

ここまでくると次にやりたいのは、確認ダイアログに表示するメッセージを、htmlにハードコーディングせずに、プログラミングしながら設定したいこと。コンポーネント利用単位でメッセージを指定できるようにしたい。
そこで、AttributeModifierを使用します。この例に限らず、htmlテンプレートにない属性を追加したり、書き換えたりすることができる優れもの。まあちょっと気持ち悪いけど、Java側のコードからonclick属性の値を指定してコンポーネントを生成します。そうするとJavaコンポーネントの生成時にメッセージを指定できるようになります。

new ConfirmButton("delete", "Really delete?");
次のJavascriptのnamespace(名前空間)の話は、Wicketとは関係なくJavascriptにおける話です。
最後に、Javascriptのソースをhtmlではなくjsファイルに記述し外だしにした際に、htmlテンプレートやJavaソースと同じように、Javascriptも同じパッケージ配下に配置したくなります。その際の参照方法です。
ResourceReferenceとHeaderContributorを使って、WebContextにJavaScriptを置くのではなく、Wicket経由でリソースにアクセスすることができます。




posted by wicket-study at 14:44 | Comment(5) | TrackBack(0) | Enjoying Web Dev. with Wicket

2008年08月18日

9章(Providing a Common Layout)レビュー

6,7,8章はちょっと飛ばします。(暇があったら6章は書きたい)9章は、複数の画面で共通のレイアウトを利用する場合のいくつかの方法を紹介しています。継承や部品化する方法が紹介されています。これは非常によく使われる内容なので、業務アプリケーションなどでも使う技術だと思います
ただし、あまりやりすぎると、Wicketの良さである、HTMLデザインをそのまま利用するという点が失われてしまうと思います。ほどほどの共通化にすべきだと思います。

まずはじめは継承です。ベースとなるページを作成し(つまり通常のWicketのページのようにHTMLとPageクラス)、それを継承するサブクラスを作成します。ベースページには抽象メソッドを定義しそれを呼び出しています。サブクラスには抽象メソッドの実装がなされています。
このようにすることで、ベースページのデザインで複数のサブクラスを作ることができ、サブクラスごとに、特化したロジックを実装することができます。

デザインをサブクラスで実装することも可能です。これはASP.NETでいうところのマスターページに似ています。
デザインの継承はwicketの独自タグを使用します。ベースページのほうには、「この部分にサブクラスのデザインが挿入されるんだぞ」という位置指定として、<wicket:child>タグを配置します。このタグのbody部分はサブクラスによって書き換えられるので、なんでもかまいません。
サブクラスには、対応するhtmlページを作成し、<wicket:extend>タグを配置します。先ほどとは逆にサブクラスのhtmlページでは、<wicket:extend>タグ内のみが利用され、タグ外は使われません。
サブクラスの<wicket:extend>内部が、<wicket:child>に埋め込まれるような形でレンダリングされます。図にすると、こんな感じです。

これで、ロジックの継承(通常のJavaの継承)と、デザインの分離が実現できます。

ここから先がややこしくなってきているのだが、継承っていうのは1つしかできないので本当にページの大もととなるデザインしか指定できません。実際にはさまざまなページ間で似たようなデザインパーツが存在するわけで、それは継承関係とは関係なくブログパーツのようにハメこんだりしたくなります。

そこで一定のデザインをPanelコンポーネントとして作成し、このPanelコンポーネントを貼り付けることでデザイン(+ロジック)を共通化することができます。Panelコンポーネントは非常の汎用的に使えるコンポーネントで、これをパーツとして自由にどこでも貼り付けることができます。

次にでてくるのがBorderコンポーネント。Panelとの違いがよく分からないのですが、今回のようにパーツとしての利用というよりも、htmlデザインのテンプレート的にPanelの継承を利用するならば、PanelではなくBorderがそれ専用に用意されているので便利ということなのでしょうか。
Borderは外側と内側のデザインを別々のhtml,javaで実装することができます。継承とは違い、ページ側からBorderコンポーネントのデザインを取り込むという形になります。

さらに複雑になってくるのですが、Borderは2つのボディ部分をもてない。そこで出てくるのがFragmentです。パネル内に、HTMLの断片を2つ配置することができます。これがあればBorder覚える必要ないんじゃないでしょうか?

ちょっとややこしいことだらけだったけど、きっとこれらは重要な内容に違いないです。もっと実践的にデザインするとその有用性が理解できるかもしれません。

ただ最初も書いたように、あまりデザインの部品化をしすぎると、htmlが断片化してあちこちに分散してしまいデザイナーがそのままデザインできるという良さが失われてしまうと思います。プログラミングする側の気持ちとしては、できるかぎり同じ箇所は部品化してしまいたい気もしますが、やりすぎはよくないと思いました。



posted by wicket-study at 15:34 | Comment(0) | TrackBack(0) | Enjoying Web Dev. with Wicket

2008年08月17日

5章(Building Interactive Pages with AJAX)

長い間、更新を怠っていましたが、夏の休暇を利用して、ある程度更新をすすめてしまおうと思います。

この章では、今流行りのAjaxを使ったコンポーネントを利用します。

まず始めは、AjaxLinkを使った部分的な更新。ページ全体のポストバックではなく、一部のみが更新されるようになる。ただし、この場合の注意点として、更新部分をあらわすWebMarkupContainerを配置しなくてはならない。ASP.NET Ajaxコンポーネントも、UpdatePanelを配置するが、それと同じようなものかな。なので、Ajaxにしない→するを単純にコンポーネントの置き換え(Link→AjaxLink)にすればよい、というわけではない。

WICKET_AJAX_DEBUGのデバッグ用コンソールは便利。通常のAjaxを利用したとたん、デバッグが難しくなるのが世の常だが、Wicketはそういった不便さをあらかじめフォローしてくれている。

次に、専用のWebMarkupContainerを配置せずに、answerラベルの更新部分だけをリフレッシュする。ただしanswerラベルは非表示にするとタグの出力をしないことになるので、Wicketのテンプレートとしては置換しようがなくなってしまう。
そこで、setOutputMarkupPlaceholderTag(true)を実行すると、タグの出力はするがstyleがdisplay:noneの状態で出力されるようになる。見えないタグを出力するという方法に切り替わる。

次はAjaxButton。あたらしいコンポーネントだが、基本的にはAjaxLinkと変わりない。Formからの入力を受け付けることができる点が異なる。
Ajaxコンポーネントは、イベントハンドラの引数にAjaxRequestTargetが渡されるが、これにaddComponentしたコンポーネントが更新される部分になるのだろう。この点がASP.NET Ajaxと少し異なる。(つまりどこを更新するかを実行時に決定できる)

またAjaxButtonを使用しなくとも、通常のHTMLのSubmitボタンをWebComponentとしてバインドし、(Webコンポーネントは汎用的で何もしないコンポーネント。WebMarkupContainerと似ているが、ボディを持たない点が違う)AjaxFormSubmitBehaverをaddすることでAjaxButtonと同じようにAjax的イベントハンドラを追加できる。この例ではonmouseoverでonsubmitと同じことをするようにしている。

別の方法として、submitボタンをそのまま配置し、formタグのonsubmitイベントにAjaxFormSubmitBefaverを追加する方法もある。この場合、formタグにfalseをreturnするために、AjaxCallDecoratorでonsubmit属性の中身に処理を文字列で追加している。



posted by wicket-study at 17:21 | Comment(0) | TrackBack(0) | Enjoying Web Dev. with Wicket

2008年06月22日

Wicket1.4のGenerics化が難航

Wicket1.4でGenerics対応するというニュースがありましたが、難航しているようです。

Wicket 1.4でのGenerics化にて大論争 - 矢野勉のはてな日記
コミッタたちが「Generics冗長すぎないか」と言い出したのですね。これはGenericsとWicketのAPIを組み合わせると冗長さが際立つ、という意味です。

コンポーネント自体が値を保持するのであれば、コンポーネントに型パラメータを指定するだけで良いのですが、Wicketはモデルを介して値を取得したりします。このアーキテクチャ、私は最初は違和感があったのですが、 今は愛してやみません。(合計値を表示するLabelなんかをAbstractReadOnlyModelで返すように設定できたりしてホント自由度が高いです。)

以前のm1がリリースされたときに試してみて、「コンポーネントとモデルで型指定するのは面倒くさい。」と思いました。
矢野さんの記事を読むMLでの議論の流れがまとめられていて分かりやすいです。本当にどちらの意見も納得&理解できて、どちらを支持するとも言いがたいですね。

正直、どちらの意見もよくわかるんですよ。Wicketは複雑そうにみえて実はシンプルでそれが好まれているのですが、Generic化によってそれが失われるのではないか、という危機感がある。一方、 私はメーリングリストに流れたとある開発者の「私はいままでシンプルだがエラー要因をもつものと、冗長だがフェイルファストとを天秤にかけられたら、常にフェイルファストを取ってきた」という意見に賛同してるんですよね。

「楽さ加減」ばかりを考えていましたが、「常にフェイルファストを取ってきた」という意見を読んで、「うーん」と考えさせられました。

悩んだ挙句の私の結論は、「ここまで冗長になるなら中途半端なものを含めてGenerics対応は要らないかなぁ」と思いました。
最近はCompoundPropertyModelにModel設定用のBeanを用意して、それに対してset/getするようになったので、あまりgetModelObjectは使わないからです。 (ListViewのpopulateItemでListItemからのgetModelObjectはよくやりますけど)
シンプルな1.3仕様のままでも、Wicketそのものが成熟して、利用が広まってくれればよいと思いました。



posted by wicket-study at 22:52 | Comment(0) | TrackBack(0) | 全般

2008年06月06日

コンポーネントを色々と試してみた

ちょっと更新が途絶えていますが、Wicketは継続して勉強中です。

PasswordTextFieldは既定でRequired

Wicketの基本的なコンポーネントについて一通り試していたときにハマったことが1つ。

PasswordTextFieldは既定でRequiredになっているんですね。それに気づかないうえに、 まだFeedbackPanelも置いていなかったので、Validationに引っかかっているのに気づかなかったです。

TextField, Button, DropDownChoiceなどをひとつずつ試しながら、 PasswordTextFieldを試したら、急にonSubmitが動作しなくなって不思議に思っていました。 確かにPasswordTextFieldは既定でRequiredで当然ともいえる。JavaDocにも、

By default this text field is required.

って書いてあるし。

DropDownChoiceやListChoiceで「選択してください」を出さない

もうひとつ。DropDownChoiceやListChoiceは、未選択状態だと「選択してください」という要素が現れて、 それが選択されている状態になる。この文字列を変更するのは、propertiesファイルで設定できることはよく知られている。でも、 そもそも「選択してください」を出したくないときはどうすればよいのか?

そもそも、DropDownChoiceならともかく、ListChoiceの場合は、「選択してください」 という要素が増えるのは変な気がする。ListChoiceの場合は、なにも選択されていない状態で表示されるのが適切ではないだろうか? 選択されていないときに出てきて、選択してしまうと要素が1つ減るのはなんか気持ち悪い。常に出ていてくれたほうがまだいいと思うのだが。

その方法は、DropDownChoiceの場合は、選択されていない状態にしなければいい。 つまりJava側のコードでモデルの値に最初の1つ目を選択しておけば、「選択してください」は表示されないくなる。 ListChoiceの場合はどうしよう???ありえない値をセットすればよい?

試してみたところgetDefaultChoiceというメソッドがあるので、これをオーバーライドして""(空文字列) を返すようにしたところ、ページが表示されたときは、DropDownChoiceは常に1つ目が選択されるようになり、 ListChoiceは未選択状態で表示されるようになった。この動きが普通だと思うんだけど、こんな実装でいいのかな。



posted by wicket-study at 13:14 | Comment(2) | TrackBack(0) | 全般

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は180日以上新しい記事の投稿がないブログに表示されております。