前回の続き
submitで画面を更新しても良いですが、Ajaxの部分更新の方が操作性が良いです。
流れとしては
これだけです。
以下の実装でやっていることは、Enum has code and propertyの性別を変更したら、すぐにMapのお菓子リストが更新されます。 (前回の実装では【更新】ボタンを押下して更新)
xhtml
追加タグ
<f:ajax listener="#{selectItemAjax.changeItem}" render="map" event="change"/>
更新トリガーとなる領域の内側に、リスナーとなるメソッドを記述します。 render="xx" は、リスナーを受け取った後、更新先の領域のHtmlのidです。
selectItemAjax.xhtml
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <meta charset="UTF-8" /> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <title>JSF SELECT ITEM</title> </h:head> <body> <form jsfc="h:form"> <h1>JSF SELECT ITEM PATTERN Ajax</h1> <dir> <h2>Enum has code and property </h2> <select jsfc="h:selectOneMenu" value="#{selectItemAjax.selectItemValueEnumCodeProperty}"> <option jsfc="f:selectItems" value="#{selectItemAjax.enumCodeProperty.values}"></option> <f:ajax listener="#{selectItemAjax.changeItem}" render="map" event="change"/> </select> </dir> <hr /> <dir> <h2>Map</h2> <select id="map" jsfc="h:selectOneMenu" value="#{selectItemAjax.selectItemValueMap}"> <option jsfc="f:selectItems" value="#{selectItemAjax.selectItemMap.values}"></option> </select> </dir> <hr /> <dir> <input type="submit" jsfc="h:commandButton" value="更新" action="#{selectItemAjax.submit()}"/> </dir> </form> </body> </html>
ManagedBean
追加したメソッド
public void changeItem(AjaxBehaviorEvent event) { this.selectItemValueMap = JsfAjaxBehaviorEvent.of(event).getValue(); ・・・ }
クラス全体
package com.mycompany.samplejsf.domain.selectitem; @Named(value = "selectItemAjax") @SessionScoped @NoArgsConstructor @Getter public class SelectItemAjaxController implements Serializable { private static final long serialVersionUID = 1L; @Setter private Integer selectItemValueEnumCodeProperty; @Setter private Object selectItemValueMap; private JsfSelectItem enumCodeProperty; private JsfSelectItem selectItemMap; private Map<Object, String> dummuyMap; @PostConstruct public void init() { this.selectItemValueEnumCodeProperty = Gender.FEMALE.getCode(); this.enumCodeProperty = JsfSelectItem.of(Gender.class); this.replaceSelectItemMap(); this.printLog("init"); } public void submit() { this.replaceSelectItemMap(); this.printLog("submit"); } public void changeItem(AjaxBehaviorEvent event) { this.selectItemValueMap = JsfAjaxBehaviorEvent.of(event).getValue(); this.replaceSelectItemMap(); this.printLog("changeItem"); } private void replaceSelectItemMap() { if (this.selectItemValueEnumCodeProperty.equals(Gender.MALE.getCode())) { this.maleSnack(); return; } this.femaleSnack(); } private void maleSnack() { Map<Object, String> map = new LinkedHashMap<>(); map.put(1, "大福"); map.put(2, "おはぎ"); map.put(3, "みたらしだんご"); map.put(4, "せんべい"); this.selectItemValueMap = map.keySet().iterator().next(); this.selectItemMap = JsfSelectItem.of(map); this.dummuyMap = map; } private void femaleSnack() { Map<Object, String> map = new LinkedHashMap<>(); map.put(5, "チョコ"); map.put(6, "クッキー"); map.put(7, "プリン"); map.put(8, "ゼリー"); this.selectItemValueMap = map.keySet().iterator().next(); this.selectItemMap = JsfSelectItem.of(map); this.dummuyMap = map; } private void printLog(String label) { System.out.println("label = " + label); System.out.println("selectItemValueEnumCodeProperty = " + selectItemValueEnumCodeProperty); System.out.println("selectItemValueEnumCodeProperty codeOf = " + EnumCodeProperty.codeOf(Gender.class, selectItemValueEnumCodeProperty)); System.out.println("selectItemValueMap = " + this.selectItemValueMap); System.out.println("selectItemValueMap value = " + this.dummuyMap.get(this.selectItemValueMap)); } }
部品クラス
たいした処理ではないですが類似実装をシンプルにするためにあえてラッパークラスを設けました。 *1
package com.mycompany.samplejsf.infrastructure.part.jsf; @RequiredArgsConstructor(staticName = "of") @EqualsAndHashCode public class JsfAjaxBehaviorEvent { private final AjaxBehaviorEvent event; public Object getValue() { UIInput uiInput = (UIInput) this.event.getComponent(); return uiInput.getValue(); } }
実行結果
Code
2018/4/17 追加
さいごに
以前、実装したものはValueChangeListenerを使ったけど、今回の整理をしている中で同じことをやろうとしたけど上手くいかなかったです。 ただ、以前の実装よりも今回のものがスッキリしているので結果として良かったように思います。