LoginSignup
0
0

More than 3 years have passed since last update.

JavaScriptで非同期処理作ってみた

Last updated at Posted at 2021-01-24

概要

セレクトボックスの値が非同期で変更するものを作ってみました。


1. セレクトボックスで群馬県を選択
2. 次のセレクトボックスには群馬県内の市だけが選択肢に入る

image.png

環境

Java13/JPA/JavaScript

参考

Ajaxを使った非同期通信
@ResponseBodyについて
ResponseEntityクラスについて

ソースコード

hello.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Ajax!</title>
</head>
<body>
    <form action="">
        <div class="form-group">
            <label th:for="ken"></label>
            <select id="ken" class="form-control">
            <option>選択してください</option>
            <option id="kenOption" th:each="ken : ${kenList}"  th:text="${ken.kenName}" th:value="${ken.kenCode}"></option>
            </select>
        </div>
        <div class="form-group">
            <label th:for="city"></label>
            <select id="city" class="form-control">
            <option>選択してください</option>
            </select>
        </div>
    </form>
    <script src="ajax.js"></script>
</body>
</html>
ajax.js
'use strict';

    //要素の取得
    const ken = document.getElementById('ken');
    const city = document.getElementById('city');

    // slectboxのchangeイベントで発火する関数
    function ajax() {

        //選択された県コードの取得
        let kenCode = ken.value;

        let request = new XMLHttpRequest();

        // onreadystatechangeは非同期。状態が変化するとコールバック関数が呼び出される。
        request.onreadystatechange = function() {

            //readyState4はレスポンスの受信完了
            if(request.readyState === 4) {

                // status200はサーバーとの通信OK
                if(request.status === 200) {

                    // レスポンスの取得
                    let resultJson = request.response;
                    console.log(resultJson);

                    let cityData;

                    // optionタグをresultJson配列の数だけ作る
                    for(let i = 0; i < resultJson.length; i++) {
                        cityData += `<option th:value="${resultJson[i].cityCode}">${resultJson[i].cityName}</option>`
                    }
                    city.innerHTML = cityData;
                }else {
                    city.innerHTML = '<option>通信失敗(´;ω;`)</option>';
                }
            }
        }
        request.open('GET', '/hello/ajax?kenCode=' + kenCode, true);
        request.responseType = 'json';
        request.send(null);
    }
    ken.addEventListener('change', ajax);

request.send(null)でリクエスト送信前に、let resultJson = request.responseでレスポンス受け取ってるのは変な気がするけどこれでOK。
基本は同期処理完了→非同期処理完了の順番なので、リクエスト送信後にレスポンスを受け取る流れになる。

AjaxController.java
@Controller
public class AjaxController {
    @Autowired
    AjaxService ajaxService;

    // 画面表示
    @GetMapping("/hello")
    public String getHello(Model model) {
        List<AjaxEntity> kenList = ajaxService.getKenNameList();
        model.addAttribute("kenList", kenList);
        return "hello";
    }

    // 非同期通信。県コードを受け取ってcityリストを返す。
    @GetMapping("/hello/ajax")
    @ResponseBody
    public ResponseEntity<List<AjaxEntity>> postAjax(@RequestParam("kenCode") int kenCode) {

        List<AjaxEntity> list = ajaxService.getCityNameList(kenCode);
        try {
            //通信成功
            return new ResponseEntity<List<AjaxEntity>>(list, HttpStatus.OK);
        } catch(Exception e) {
            //通信失敗
            return new ResponseEntity<List<AjaxEntity>>(HttpStatus.BAD_REQUEST);
        }
    }
}

@ResponseBodyをつけると@Controllerの戻り値にString以外も指定できる。
今回はEntityクラスのList(配列)をResponseEntity入れて戻り値にしている。
@RestControllerでも似たようなことができるっぽい。

AjaxService.java
@Service
public class AjaxService {
    @Autowired
    AjaxRepository ajaxRepository;

    /**
     * 全県名と全県コードのリストを取得する
     */
    public List<AjaxEntity> getKenNameList(){

        List<String[]> list = ajaxRepository.getKenNameList();
        List<AjaxEntity> aeList = new ArrayList<>();

        for(String[] array : list) {
            int kenCode = Integer.parseInt(array[0]);
            String kenName = String.valueOf(array[1]);

            AjaxEntity ae = new AjaxEntity();
            ae.setKenCode(kenCode);
            ae.setKenName(kenName);
            aeList.add(ae);
        }
        return aeList;
    }


    /**
     * 同一県内の市をリストで返す
     *
     * 例:群馬県を選択すると、群馬県内の市リストが返る
     */
    public List<AjaxEntity> getCityNameList(int kenCode){

        List<String[]> list = ajaxRepository.getCityNameList(kenCode);
        List<AjaxEntity> aeList = new ArrayList<>();

        for(String[] array : list) {
            int cityCode = Integer.parseInt(array[0]);
            String cityName = String.valueOf(array[1]);

            AjaxEntity ae = new AjaxEntity();
            ae.setCityCode(cityCode);
            ae.setCityName(cityName);
            aeList.add(ae);
        }
        return aeList;
    }
}
AjaxRepository.java
@Repository
public interface AjaxRepository extends JpaRepository<AjaxEntity, Integer>{

    @Query(value = "select distinct kenCode, kenName from AjaxEntity a")
    List<String[]> getKenNameList();

    @Query(value = "select distinct cityCode, cityName from AjaxEntity a where kenCode = :kenCode")
    List<String[]> getCityNameList(@Param("kenCode") int kenCode);
}
AjaxEntity.java
@Data
@Entity
@Table(name="address")
public class AjaxEntity {

    @Id
    @Column(name="kencode")
    private Integer kenCode;

    @Column(name="citycode")
    private Integer cityCode;

    @Column(name="kenname")
    private String kenName;

    @Column(name="cityname")
    private String cityName;
}
0
0
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
0
0