코드 그라데이션

Thymeleaf 통합 (4) 체크 박스 - 멀티 본문

Spring/Thymeleaf

Thymeleaf 통합 (4) 체크 박스 - 멀티

완벽한 장면 2023. 12. 5. 14:32

체크 박스 - 멀티

체크 박스를 멀티로 사용해서, 하나 이상을 체크할 수 있도록.

 

등록 지역

  • 서울, 부산, 제주
  • 체크 박스로 다중 선택할 수 있다.

 

 

등록 폼 수정

@GetMapping("/add")
public String addForm(Model model) {
    model.addAttribute("item", new Item());

    Map<String, String> regions = new LinkedHashMap<>(); // HashMap 쓰면 순서가 보장x
    regions.put("SEOUL", "서울");
    regions.put("BUSAN", "부산");
    regions.put("JEJU", "제주");
    model.addAttribute("regions", regions);
    return "form/addForm";
}

 

    Map<String, String> regions = new LinkedHashMap<>(); // HashMap 쓰면 순서가 보장x
    regions.put("SEOUL", "서울");
    regions.put("BUSAN", "부산");
    regions.put("JEJU", "제주");
    model.addAttribute("regions", regions);

그런데, 생각해보면 이것은 등록 폼에만 넣는 게 아니라 상품 상세, 수정 폼에도 들어가고 해야 한다.

 

그럼 코드를 따로 빼는 게 맞죠.

/**
 * 이렇게 하면 이 컨트롤러를 호출할 때는
 * 항상 얘가 ModelAttribute 에 자동으로 addAttribute 되어가지고
 * Model에 무조건 담긴다.
 * 그래서 일일이 메서드에 추가했던 코드를 다시 다 지울 수 있게 된다.
 * @return
 */
@ModelAttribute("regions")
public Map<String, String> regions() {
    Map<String, String> regions = new LinkedHashMap<>();
    regions.put("SEOUL", "서울");
    regions.put("BUSAN", "부산");
    regions.put("JEJU", "제주");
    return regions;
}

예를 들어, editForm이 호출이 되면, 위의 얘의 내용이 자동으로 모델에 담기게 된다는 뜻.

 

@ModelAttribute의 특별한 사용법

 


addForm.html - 추가

single checkbox 아래 영역에 추가

<!-- multi checkbox -->
<div>
    <!-- "등록 지역" 섹션을 표시하는 div -->
    <div>등록 지역</div>

    <!-- Thymeleaf 반복문으로 지역 목록을 처리하며, 각 지역에 대한 체크박스를 생성 -->
    <div th:each="region : ${regions}" class="form-check form-check-inline">
        <!-- 체크박스 입력 요소 -->
        <input type="checkbox" th:field="*{regions}" th:value="${region.key}"
               class="form-check-input">

        <!-- 체크박스 레이블 요소 -->
        <label th:for="${#ids.prev('regions')}"
               th:text="${region.value}" class="form-check-label">서울</label>
    </div>
</div>

 

 

부연설명

<div th:each="region : ${regions}" class="form-check form-check-inline">

  • 이 요소는 Thymeleaf의 반복 지시문인 th:each를 사용하여 반복된다.
  • ${regions}는 Thymeleaf 컨텍스트에서 제공되는 컬렉션 또는 리스트를 나타내며, region은 각 요소를 대표하는 변수.
  • 이 요소에는 "form-check" 및 "form-check-inline" 클래스가 지정되어 있다.
  • 이러한 클래스는 일반적으로 CSS 스타일링을 적용하는 데 사용된다.

 

<input type="checkbox" th:field="*{regions}" th:value="${region.key}" class="form-check-input">

  • 이 부분은 체크박스를 생성하는 부분입니다. th:field 속성은 Thymeleaf의 폼 바인딩을 사용하며,                                  *{regions}는 해당 체크박스의 값을 연결할 모델 속성을 나타낸다.
  • th:value는 각 체크박스의 값으로 ${region.key}를 사용하고 있으며, 이 값은 반복문에서 현재 요소의 키를 나타낸다.
  • class="form-check-input"는 체크박스에 CSS 클래스를 지정한다.

 

<label th:for="${#ids.prev('regions')}" th:text="${region.value}" class="form-check-label">서울</label>

  • 이 부분은 체크박스 옆에 레이블을 생성한다.
  • th:for 속성은 레이블을 체크박스와 연결하고, ${#ids.prev('regions')}는 이전 폼 컨트롤의 ID를 참조.
  • th:text는 레이블의 텍스트로 ${region.value}를 사용하고 있으며, 이 값은 반복문에서 현재 요소의 값을 나타낸다.
  • class="form-check-label"는 레이블에 CSS 클래스를 지정한다

 

실행하면

새로 생김

 

페이지 소스 보기 해보면

 

반복문을 사용해서 돌리는데,

그 돌리는 것은 아까 처음에 추가했던

@ModelAttribute("regions")
public Map<String, String> regions() {
    Map<String, String> regions = new LinkedHashMap<>();
    regions.put("SEOUL", "서울");
    regions.put("BUSAN", "부산");
    regions.put("JEJU", "제주");
    return regions;
}

 요게 한다.

 

 

설명

 

 

each로 체크박스가 반복 생성된 결과 - id 뒤에 숫자가 추가


 

로그 출력

FormItemController.addItem() 에 코드 추가

log.info("item.regions={}", item.getRegions());

 

편의를 위해 application.properties의 옵션을 끄고 돌리겠다.

 

실행 결과

regions를 List로 지정했으므로 값 두개가 잘 들어온다.

 

이번엔 지역 선택 하지 않고 등록해보면

 

 

빈 배열이 들어옴을 확인할 수 있음.

 

로그: item.regions=[]


item.html에도 추가

<!-- multi checkbox -->
<div>
    <div>등록 지역</div>
    <div th:each="region : ${regions}" class="form-check form-check-inline">
        <input type="checkbox" th:field="${item.regions}" th:value="${region.key}" class="form-check-input" disabled>
        <label th:for="${#ids.prev('regions')}"
               th:text="${region.value}" class="form-check-label">서울</label>
    </div>
</div>

item에는 th:object가 없다!!!

 


타임리프의 체크 확인

 

 th:field="${item.regions}" th:value="${region.key}" 이렇게 있으면

item.regions 에는 처음에 내가 선택한 두 개(서울, 부산) 이 들어가 있다.

value에는 값이 하나씩 만들어지니까 th:value 에는 값이 서울, 부산, 제주 가 들어가 있다.

 

첫 번째는  region.key 얘가 서울인데 서울 값이 item.regions에 있나 비교해보고, 있으니까 checked 에 값을 넣어주고,

두 번째는  region.key 얘가 부산인데 부산 값이 item.regions에 있나 비교해보고, 있으니까 checked 에 값을 넣어주고,

세 번째는  region.key 얘가 제주인데 제주 값이 item.regions에 있나 비교해보고, 없으니까 넣지 않는다는 것.

 


editForm.html - 추가

<!-- multi checkbox -->
<div>
    <div>등록 지역</div>
    <div th:each="region : ${regions}" class="form-check form-check-inline">
        <input type="checkbox" th:field="${item.regions}" th:value="${region.key}" class="form-check-input">
        <label th:for="${#ids.prev('regions')}"
               th:text="${region.value}" class="form-check-label">서울</label>
    </div>
</div>
728x90
Comments