LoginSignup
1
2

More than 5 years have passed since last update.

【JSF】ajaxタグを用いたセレクトボックス要素の動的取得

Posted at

概要

JSFの非同期通信タグ<f:ajax>を用いて
1つ目のセレクトボックスと2つ目のセレクトボックス内容を連動させてみる。

環境

完成イメージ

【図1.完成図】
ajax4.png

初期状態では2つ目のセレクトボックスは空です。

1つめのセレクトボックスで人物を選択すると

2つめのセレクトボックスにその人物が持っているスキルのリストが組み込まれ、選択できる状態になります。

実装(1)

まずはDTOを利用せず、リストの要素に
SelectItemクラスを利用したパターンから。(javax.faces.model.SelectItem)
※DTO:IT用語辞典

SelectBean.java
package bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.model.SelectItem;

@ManagedBean
@ViewScoped
public class SelectBean implements Serializable{

    /*** 本来DB等から拾って来るデータ ***************************************************/
    //従業員マスタ
    static List<SelectItem> EMPLOYEE_LIST;
    static {
        EMPLOYEE_LIST = new ArrayList<SelectItem>();
        EMPLOYEE_LIST.add(new SelectItem("E0000","選択して下さい"));
        EMPLOYEE_LIST.add(new SelectItem("E0001","テスト一郎"));
        EMPLOYEE_LIST.add(new SelectItem("E0002","テスト二郎"));
        EMPLOYEE_LIST.add(new SelectItem("E0003","テスト三郎"));
    }

    //スキルマスタ
    private static Map<Object,List<SelectItem>> SKILL_MAP;
    static {
        List<SelectItem> emp1Skills = new ArrayList<SelectItem>();
        emp1Skills.add(new SelectItem("skill_01","Java"));
        emp1Skills.add(new SelectItem("skill_02","JSP"));
        emp1Skills.add(new SelectItem("skill_03","JavaScript"));

        List<SelectItem> emp2Skills = new ArrayList<SelectItem>();
        emp2Skills.add(new SelectItem("skill_01","Java"));
        emp2Skills.add(new SelectItem("skill_03","JavaScript"));
        emp2Skills.add(new SelectItem("skill_05","C++"));

        List<SelectItem> emp3Skills = new ArrayList<SelectItem>();
        emp3Skills.add(new SelectItem("skill_04","C"));
        emp3Skills.add(new SelectItem("skill_05","C++"));
        emp3Skills.add(new SelectItem("skill_06","VB.net"));

        SKILL_MAP = new HashMap<Object,List<SelectItem>>();
        SKILL_MAP.put("E0001", emp1Skills);
        SKILL_MAP.put("E0002", emp2Skills);
        SKILL_MAP.put("E0003", emp3Skills);
    }
    /********************************************************************************/

    //選択された従業員
    private String selectedEmployee;
    //従業員リスト
    private List<SelectItem> empList = EMPLOYEE_LIST;
    //スキルリスト
    private List<SelectItem> skillList;

    /*** method ****************************************************************/
    public void changeSkillList(){
        this.skillList = SKILL_MAP.get(this.selectedEmployee);
    }

    /*** getter setter *********************************************************/
    public String getSelectedEmployee() {
        return selectedEmployee;
    }

    public void setSelectedEmployee(String selectedEmployee) {
        this.selectedEmployee = selectedEmployee;
    }

    public List<SelectItem> getSkillList() {
        return skillList;
    }

    public void setSkillList(List<SelectItem> skillList) {
        this.skillList = skillList;
    }

    public List<SelectItem> getEmpList() {
        return empList;
    }

    public void setEmpList(List<SelectItem> empList) {
        this.empList = empList;
    }

}
index.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
    <title>Ajax</title>
</h:head>
<h:body>

<h:form>
    <!-- ajaxによる非同期通信をあれこれしている部分 -->
    <div>
        <f:ajax event="change" render="skill" listener="#{selectBean.changeSkillList()}">
            <h:selectOneMenu value="#{selectBean.selectedEmployee}">
                <f:selectItems value="#{selectBean.empList}" />
            </h:selectOneMenu>
        </f:ajax>
    </div>

    <!-- ajaxによる非同期通信後 更新されるコンポーネント -->
    <div>
        <h:selectOneMenu id="skill">
            <f:selectItems value="#{selectBean.skillList}" />
        </h:selectOneMenu>
    </div>
</h:form>

</h:body>
</html>

まず今回DBを用いていないのでマスタデータは適当に用意しています。

フィールドとして
1.選択された従業員のID
2.従業員リスト
3.選択された従業員のスキルリスト

を持たせます。

<f:ajax>タグのlistenerに呼び出されるメソッドの中で
マスタのSKILL_MAPの中から「選択された従業員のID」に対応するスキルリストを取得して
フィールドの「選択された従業員のスキルリスト」に格納します。

今回<f:ajax>タグで用いられている属性を簡単に説明します。

  • event :change(値が変更された)、keyup(キーボードのキーが上がった)等様々なタイミングでajaxの処理を開始します。
  • render :ajaxの処理が終わり、最終的に更新したいコンポーネントを指定します。複数ある場合は半角スペース区切りで指定します。
  • listener :eventが確認された際、呼び出すメソッドを指定します。

実装(2)

次にDTOクラスを利用したいパターン。
※DTO:IT用語辞典

まずDTO、従業員とスキルの2クラスを定義します。

Employee.java
package dto;

/* 従業員クラス */
public class Employee {

    private String id ;
    private String name ;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Skill.java
package dto;

/* スキルクラス */
public class Skill {

    private String skillId;
    private String skillName;

    public String getSkillId() {
        return skillId;
    }
    public void setSkillId(String skillId) {
        this.skillId = skillId;
    }
    public String getSkillName() {
        return skillName;
    }
    public void setSkillName(String skillName) {
        this.skillName = skillName;
    }
}




次に管理Bean。

SelectBean.java
package bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

import dto.Employee;
import dto.Skill;

@ManagedBean
@ViewScoped
public class SelectBean implements Serializable{

    /*** 本来DBから拾って来るデータ ***************************************************/
    //従業員マスタ
    static List<Employee> EMPLOYEE_LIST;
    static {
        EMPLOYEE_LIST = new ArrayList<Employee>();
        EMPLOYEE_LIST.add(new Employee("E0000","選択して下さい"));
        EMPLOYEE_LIST.add(new Employee("E0001","テスト一郎"));
        EMPLOYEE_LIST.add(new Employee("E0002","テスト二郎"));
        EMPLOYEE_LIST.add(new Employee("E0003","テスト三郎"));
    }

    //スキルマスタ
    private static Map<Object,List<Skill>> SKILL_MAP;
    static {
        List<Skill> emp1Skills = new ArrayList<Skill>();
        emp1Skills.add(new Skill("skill_01","Java"));
        emp1Skills.add(new Skill("skill_02","JSP"));
        emp1Skills.add(new Skill("skill_03","JavaScript"));

        List<Skill> emp2Skills = new ArrayList<Skill>();
        emp2Skills.add(new Skill("skill_01","Java"));
        emp2Skills.add(new Skill("skill_03","JavaScript"));
        emp2Skills.add(new Skill("skill_05","C++"));

        List<Skill> emp3Skills = new ArrayList<Skill>();
        emp3Skills.add(new Skill("skill_04","C"));
        emp3Skills.add(new Skill("skill_05","C++"));
        emp3Skills.add(new Skill("skill_06","VB.net"));

        SKILL_MAP = new HashMap<Object,List<Skill>>();
        SKILL_MAP.put("E0001", emp1Skills);
        SKILL_MAP.put("E0002", emp2Skills);
        SKILL_MAP.put("E0003", emp3Skills);
    }
    /********************************************************************************/

    //選択された従業員
    private String selectedEmployee ;
    //従業員リスト
    private List<Employee> empList = EMPLOYEE_LIST;
    //スキルリスト
    private List<Skill> skillList;

    /*** method ****************************************************************/
    public void changeSkillList(){
        this.setSkillList(SKILL_MAP.get(selectedEmployee));
    }

    /*** getter setter *********************************************************/
    public String getSelectedEmployee() {
        return selectedEmployee;
    }

    public void setSelectedEmployee(String selectedEmployee) {
        this.selectedEmployee = selectedEmployee;
    }

    public List<Skill> getSkillList() {
        return skillList;
    }

    public void setSkillList(List<Skill> skillList) {
        this.skillList = skillList;
    }

    public List<Employee> getEmpList() {
        return empList;
    }

    public void setEmpList(List<Employee> empList) {
        this.empList = empList;
    }
}

記述はほぼ変更無しですが、SelectItemクラスを利用していた部分がDTOのクラスに変更されています。

最後にView。

index.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
    <title>Ajax</title>
</h:head>
<h:body>

<h:form>
    <!-- ajaxによる非同期通信の -->
    <div>
        <f:ajax event="change" render="skill" listener="#{selectBean.changeSkillList()}">
            <h:selectOneMenu value="#{selectBean.selectedEmployee}">
                <f:selectItems value="#{selectBean.empList}" var="emp" itemLabel="#{emp.name}" itemValue="#{emp.id}"/>
            </h:selectOneMenu>
        </f:ajax>
    </div>

    <!-- ajaxによる非同期通信後 更新されるコンポーネント -->
    <div>
        <h:selectOneMenu id="skill">
            <f:selectItems value="#{selectBean.skillList}" var="sk" itemLabel="#{sk.skillName}" itemValue="#{sk.skillId}" />
        </h:selectOneMenu>
    </div>
</h:form>

</h:body>
</html>

変更された部分は、<f:selectItems>タグの中に
属性:var/itemLabel/itemValue
を追加している点です。

補足

非同期通信とは

クライアントがページ全体をリクエストして、サーバからの応答を待っている間何も出来ない同期通信に対し
非同期通信ではページの一部機能に必要な情報のみリクエストし、レスポンスが返ってくるまでの間も平行して他の処理を行うことが出来ます。
例の1つとして、検索エンジンのサジェスト機能がそれにあたります。

サジェスト.png

keyup等のイベントで、キーが入力された都度検索候補の情報をリクエストしているのだと思います。

※非同期通信:@IT リッチクライアント用語辞典

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2