選択肢を連動させる
親の項目で子の選択肢を絞る(都道府県→市区町村)。定義に書くか、Repository から引く。検索条件でも同じ。
都道府県を選んだら、市区町村の選択肢がその県のものだけになる。業務システムでは定番の動きで、これまでは自分でコードを書くしかなかった。定義で書けるようにしたのがこれ。
親の項目を optionsFrom で指して、選択肢それぞれに「どの親の値のときに出るか」を when で書く。
- { field: prefecture, label: 都道府県, type: select,
options: [ { value: tokyo, label: 東京都 }, { value: osaka, label: 大阪府 } ] }
- field: city
label: 市区町村
type: select
optionsFrom: prefecture
options:
- { value: shibuya, label: 渋谷区, when: tokyo }
- { value: kita, label: 北区, when: osaka }
- { value: other, label: その他 }when を書いていない選択肢(上の「その他」)は常に出る。「未選択」「不明」「その他」のような、親に関係なく要るものに使う。
親を選ぶまで、子は空
親が未入力のあいだ、when 付きの選択肢は出ない。全部出しておいて後で絞るのではなく、選べる状態になってから出す。
親を選び直したときに、子に入っていた値が新しい選択肢に無ければその値は捨てる。東京都・渋谷区と入れたあとで大阪府に変えたら、市区町村は空に戻る。放っておくと「大阪府なのに渋谷区」で保存できてしまうので、消えて選び直してもらう方を選んだ。ここは知らないと驚くところなので、先に書いておく。
選択肢がデータのときは Repository から引く
市区町村を全部定義に書くわけにはいかない。選択肢そのものがマスタにあるなら optionsSource で引く。
- field: city
label: 市区町村
type: select
optionsFrom: prefecture
optionsSource:
repository: cityRepository # 自分で登録した Repository
value: code # 行のどの項目を値にするか
label: name # 行のどの項目を表示するか
parentKey: prefecture # 親の値を、この名前で絞り込み条件として渡す引き先は一覧画面と同じ Repository。フレームワークは HTTP も SQL も知らないので、{ prefecture: "osaka" } という条件で search を呼ぶところまでしかしない。どう絞るかは実装した人の領分。
親が未入力のあいだは引きにも行かない(全件返ってきても連動の意味がないので)。親を変えれば引き直し、同じ親のままなら1回しか引かない。
どちらで書くか
定義に書く(when) | Repository から引く(optionsSource) | |
|---|---|---|
| 向いている | 区分・種別・ステータスのような固定の分類 | マスタにあるもの(取引先、品目、市区町村) |
| 増えたとき | 定義を直してリリース | データを足すだけ |
| オフラインでも動くか | 動く | Repository 次第 |
両方書いた場合は引いてきた方が勝つ。書いた options が黙って無視される形になるので、hatake validate が警告する。
検索条件でも同じ
検索欄(search.filters)でも同じキーが同じ意味で使える。「絞ってから探す」は入力より先に欲しがられるやつ。
search:
filters:
- { field: category, label: カテゴリ, type: select, operator: equals,
options: [ { value: food, label: 食品 }, { value: drink, label: 飲料 } ] }
- field: subCategory
label: 細目
type: select
operator: equals
optionsFrom: category
options:
- { value: vegetable, label: 野菜, when: food }
- { value: juice, label: ジュース, when: drink }判定は入力項目とまったく同じものを使っている(違うのは「いまの値」がレコードか検索欄かだけ)。親を変えて選べなくなった条件は捨てられるので、絞った先に無い条件で検索してしまうことがない。
範囲指定(operator: between)の条件は値を2つ持つので、親にはできない。
書けるキー
| キー | 書く場所 | 型 | 必須 | 既定値 | 有効なページ種別 | 説明 |
|---|---|---|---|---|---|---|
optionsFrom | field | string | 任意 | — | crud dashboard detail form master report search wizard | Parent field name. The options shown are those whose when matches the parent's current value (plus any option without a when). Changing the parent clears a child value that is no longer offered. |
optionsFrom | filter | string | 任意 | — | crud dashboard master report search | Parent filter name in the same search area. The options shown are those whose when matches the parent's current value (plus any option without a when). Changing the parent clears a child value that is no longer offered. |
when | option | `string | number | boolean` | 任意 | — |
optionsSource | field | object → optionsSource | 任意 | — | crud dashboard detail form master report search wizard | Fetch a field's options from a repository instead of listing them. The framework knows no HTTP or SQL: it asks the repository the application registered, passing the parent value as a filter when parentKey is set. |
optionsSource | filter | object → optionsSource | 任意 | — | crud dashboard master report search | Fetch a field's options from a repository instead of listing them. The framework knows no HTTP or SQL: it asks the repository the application registered, passing the parent value as a filter when parentKey is set. |
options | field | array → option | 任意 | — | crud dashboard detail form master report search wizard | — |
options | filter | array → option | 任意 | — | crud dashboard master report search | Options for select-style filters. |
この表は spec/reference.json から生成している(JSON Schema が正)。手元では npx hatake reference <キー名> で同じものが引ける。
近い例
例は丸ごと写して直すのが一番速い。以下は CI で検証済み(そのまま動く形)。
| ファイル | 種別 | 画面 | どういうときに使うか |
|---|---|---|---|
product_search.yaml | search | 商品照会 | 検索して一覧を見るだけ(登録も更新もさせない)画面が欲しい |
customer_form.yaml | form | 顧客入力 | 一覧を持たない単票の入力画面が欲しい(新規と編集を1枚で) |
よくある間違い
選択肢の連動を、子の項目を親の値ごとに並べて visibleWhen で出し分けて作る
なぜ駄目か 親の値が3つなら項目が3つになり、保存される項目名も3つに分かれる(cityTokyo / cityOsaka …)。組み合わせが増えると破綻し、データの形まで歪む。
こう直す 子は1項目のままにして、optionsFrom で親を指し、各選択肢に when を書く。選択肢がデータなら optionsSource で Repository から引く。
page:
type: form
id: customer_form
title: 顧客入力
repository: customerRepository
form:
sections:
- fields:
- { field: prefecture, label: 都道府県, type: select,
options: [{ value: tokyo, label: 東京都 }, { value: osaka, label: 大阪府 }] }
- field: city
label: 市区町村
type: select
optionsFrom: prefecture
options:
- { value: shibuya, label: 渋谷区, when: tokyo }
- { value: kita, label: 北区, when: osaka }spec/pitfalls.json から生成。各項目は CI で検証済み(間違いは本当に落ち、正しい方は本当に通る)。手元では npx hatake pitfalls <キー名>。
実物を見る
デモアプリの「受注入力」がこれを使っている。 デモを開く