reactive-web: Lift をシンプルに

要素

RElem

イベントとプロパティはしばしばそれだけで使用することができます。というのも、イベントやプロパティは NodeSeq=>NodeSeq 関数または Elem=>Elem 関数だからです。一方、トレイト RElem も存在します。このトレイトは直接使用することもできれば、このトレイトを継承するクラスとトレイトを経由して使用することもできます。RElem に含まれているのは、基本の scala.xml.Elem、一意の id、一連の DomEventSource および DomProperty、さらにこれまでにレンダリング先となった一連の Page です。RElemrender を呼び出すと、Elem が返されますが、render は暗黙のスコープを介して (スコープを明示的に渡さない場合) 現在の Page を見つけ、これを記録し、すべての DomProperty に追加します。ついで scala.xml.Elem が返されます。返される scala.xml.Elem は、まず baseElem から始めて、id 属性を追加し、プロパティの現在の値に対応する属性を追加し、リスナーが追加されている DomEventSource のイベントハンドラを追加することによって生成されます。

RElemnet.liftweb.util.Bindable を継承しているので、インスタンスを bind 式の中で直接使うことができ (Helpers.bind を使う場合も、CSS セレクタバインディングを使う場合も)、render を呼び出す必要がありません。Lift は asHtml メソッドを呼び出し、このメソッドが、CurrentPage RequestVar に入っている Page を指定して render を呼び出します (Page を設定する必要はありません。リクエストの中で初めてその値が読み取られたときに、新しい Page が作成され、これがそのリクエストの以降の部分でも保持されます)。

RElem のインスタンスはさまざまな方法で取得できます。もちろん、プログラマが自分で継承することもできます。form 要素などの HTML 要素に対応する数多くのトレイト、クラス、およびファクトリが存在します。このうち汎用のファクトリ RElem.apply(parentElem: scala.xml.Elem, children: RElem*) は、通常の scala.xml.Elem (および場合によってはその内側に置くいくつかの RElems)、およびそのオーバーロードである RElem.apply(text: String) をラップし、テキストを含む <span> をラップする RElem を返します。また、CellRepeater があります。

Cell

要素のコンテンツを動的なものにする場合は、Cell を使うとよいでしょう。Cell は、RElem を継承するトレイトです。このトレイトは、コンテンツ (すなわち子要素) が Signal[NodeSeq] によって表現される RElem を管理するのに使われます。このトレイトは、このトレイトを継承する実装を介して利用することができます。しかし、ファクトリも存在していて、これを CSS セレクタバインディングで使用することで、任意の要素 (テンプレートで定義されているものでも) のコンテンツを動的にすることができます。

このファクトリは、実際には NodeSeq=>NodeSeq を取り、NodeSeq=>NodeSeq を返します。返された関数が呼び出されると、外側の要素として渡された (テンプレート) NodeSeq を使って RElem をインスタンス化します。その子は、渡されたバインディング関数をテンプレート要素の子に対して実行することで、生成されます。

Repeater

Repeater は、SeqSignal に対応する Cell です。CellSignal を使用してそのコンテンツ全体を定義する (Signal の値が変更されるたびに該当要素のコンテンツ全体を置き換える必要がある) のに対し、RepeaterSeqSignal[NodeSeq] を使用します。これは非常に強力な機能です。具体的には、アイテムの動的な集合を完全に宣言的に表現することができ、しかも (細かい部分は気にすることなく) 項目が変更されると更新の必要な部分だけが更新されます。

さらに、Select (HTML select 要素に対応) などの実装用に、Repeater には Cell に似たファクトリがあります。

具体的には、テンプレート要素の子に対して実行するバインディング関数をファクトリに渡すと、ファクトリからバインディング関数が返され、Lift がこれをテンプレートに対して実行します。実行されると、関数はテンプレートからの要素を外側の要素として使う RElem をインスタンス化し、ファクトリに渡したバインディング関数が各要素に対して実行されます。