[Weblocks] Weblocks - widgets - DataGrid, GridEdit
Common LispのWeb Application Framework, Weblocksには便利な widgetがいろいろと用意されています。前回の Login widgetのように Webアプリケーションを作っていると使うことになる画面部品は標準で用意されていますし、それ以外のモノも結構簡単に自分で定義することが出来ます。今回は標準で用意されたwidgetの中から DataGrid と GridEditの2つです。
なぜ2つ同時かと言うと、DataGridは GridEditのReadOnly版だからです。使い方や見た目はほぼ同じっぽいので纏めました。
DataGrid & GridEditは表を作成する為のWidgetです。GridEditは表への追加、変更、削除の機能も付いています。
GridEditで定義されている Slotは以下。
drilldown-type | (or :view :edit)。 |
:viewを指定すると表のレコードをクリックした際に詳細内容表示→ [Modify]リンク押下 → 内容編集という流れになる。 | |
:editを指定すると詳細表示を飛ばして、即内容編集可能な状態になる。 |
DataGridではSlotは定義していませんが dataseqというWidgetを継承しています(ちなみにGridEditはDataGridを継承しています)。
DataSeqのslotは以下。
view | 一覧表示時のview。 |
defviewの際、:type tableを指定したviewを使用。 | |
data-class | 一覧表示の1レコードを表すクラス名 |
class-store | 特に指定しなければ data-classの内容から勝手に生成 |
on-query | まだ調べてない。 |
allow-sorting-p | 一覧のヘッダをクリックしたときにソートするか否か。 |
sort | ソート条件。(ソート項目名 . :asc)か(ソート項目名 . :desc) |
allow-select-p | 削除のための選択チェックボックスを付けるか否か。 |
nilにすると レコードの削除が出来なくなる。 | |
selection | まだ調べてない。 |
allow-drilldown-p | レコードをクリックした際の詳細表示、内容編集フォームを出さない。 |
on-drilldown | レコードクリック時に呼び出す関数? |
drilled-down-item | まだ調べてない。 |
autoset-drilled-item-p | まだ調べてない。 |
allow-operations-p | まだ調べてない。 |
item-ops | まだ調べてない。 |
common-ops | まだ調べてない。 |
allow-pagination-p | ページングするか否か |
pagination-widget | ページングwidget。指定しなければ勝手に作られる。 |
show-total-items-count-p | 総レコード数を表示するか否か。デフォルトでは表示(t) |
flash | 追加/変更/削除後のメッセージ用Widget。普通はflash widget。 |
rendered-data-sequence | まだ調べてない。 |
調べてないばかりでスミマセン・・・
また GridEditは dataedit-mixinというクラスを継承しています。dataedit-mixinのslotは以下。
on-add-item | 調べてないけど、レコード追加時に呼ばれる関数? |
on-add-item-completed | 調べてないけど、レコード追加完了時に呼ばれる関数? |
allow-add-p | 新規レコードを追加するための ADDボタンを付けるか否か。 |
show-add-form-when-empty-p | t を指定した場合、データが0件のときは最初から新規追加フォームが開いている。 |
flash-message-on-first-add-p | t を指定した場合、1レコード目の登録時も登録完了メッセージを表示。 |
on-delete-items | 調べてないけど、レコード削除時に呼ばれる関数? |
on-delete-items-completed | 調べてないけど、レコード削除完了時に呼ばれる関数? |
cascade-delete-mixins-p | まだ調べてない。 |
allow-delete-p | レコードを削除するための DELETEボタンをつけるか否か。 |
item-data-view | データの View。defviewの際、:type dataで定義した view。 |
item-form-view | フォームの View。defviewの際、:type formで定義した view。 |
auteset-drilled-down-item-p | initargが無い・・・ |
ui-state | まだ調べてない。 |
item-widget | initargが無い・・・ |
dataedit-mixinでとても大事なのが item-data-viewと item-form-viewの2つです。
この2つはそれぞれ 詳細表示時の表示項目、新規追加/データ編集時の表示項目として使用されます。*1
;;; 1. 表示するクラスを定義 (defclass user (store-template) ((id) (login-id :accessor user-login-id :initarg :login-id :type string) (password :accessor user-password :initarg :password :type string) (name :accessor user-name :initarg :name :type string) (birthday :accessor user-birthday :initarg :birthday))) ;;; 2. TABLE VIEWを定義 (defview user-table-view (:type table :inherit-from '(:scaffold user)) (id :hidep t) (login-id) (password :hidep t) (name :label "氏名") (birthday :label "誕生日" :reader (lambda (user) (multiple-value-bind (s m h d mo y) (decode-universal-time (user-birthday user)) (declare (ignore s m h)) (format nil "~4,'0d/~2,'0d/~2,'0d" y mo d))))) ;;; 3. DATA VIEWを定義 (defview user-data-view (:type data :inherit-from '(:scaffold user)) (id :hidep t) (login-id) (password :hidep t) (name :label "氏名") (birthday :label "誕生日" :reader (lambda (user) (multiple-value-bind (s m h d mo y) (decode-universal-time (user-birthday user)) (declare (ignore s m h)) (format nil "~4,'0d/~2,'0d/~2,'0d" y mo d))))) ;;; 4. FORM VIEWを定義 (defview user-form-view (:type form :inherit-from '(:scaffold user)) (id :hidep t) (login-id :requiredp t) (password :label "パスワード" :reader (lambda (obj) "") :writer (lambda (value obj) (setf (user-password obj) (hash-password value)))) (name :label "氏名" :requiredp t) (birthday :label "誕生日" :reader (lambda (user) (multiple-value-bind (s m h d mo y) (decode-universal-time (user-birthday user)) (declare (ignore s m h)) (format nil "~4,'0d/~2,'0d/~2,'0d" y mo d))) :writer (lambda (value obj) (setf (slot-value obj 'birthday) (yyyy/mm/dd->utime value))))) ;;; 5. 初期ページを作る関数 (defun initial-page () (make-instance 'widget :children (list (f_% (with-html (:p "Data Grid"))) (make-instance 'datagrid :name 'user-data-grid :data-class 'user :view 'user-table-view) (f_% (with-html (:hr) (:p "Grid Edit[DrillDown-Type=:view]"))) (make-instance 'gridedit :name 'user-edit-grid-view :drilldown-type :view :data-class 'user :view 'user-table-view :item-data-view 'user-data-view :item-form-view 'user-form-view ) ))) ;;; 6. 最初に呼ばれてるっぽい関数 (defun init-user-session (comp) (with-flow comp (yield (initial-page)) ))
やっていることは
- 一覧に表示するためのクラスを定義(項目 id login-id password name birthday)
- TABLE VIEWを定義(userクラスから自動生成, idとpasswordは非表示, birthdayはyyyy/mm/dd形式)
- DATA VIEWを定義(userクラスから自動生成, idとpasswordは非表示, birthdayはyyyy/mm/dd形式)
- FORM VIEWを定義(userクラスから自動生成, idは非表示, passwordは空欄表示で入力値は 暗号化して保存, birthdayはyyyy/mm/dd形式で表示し、yyyy/mm/dd形式の文字列をuniversal-timeに変換して保存)
- DataGridとGridEditを画面表示するための関数を定義
- Sessionが無い状態で表示される画面にする
自分で書いておいてなんですが、この説明全然わかんない。
*1:viewを作成する defviewはまた後日