타임리프는 자바스크립트에서 타임리프를 편리하게 사용할 수 있는 자바스크립트 인라인 기능을 제공합니다. 자바스크립트 인라인 기능은 다음과 같이 적용하면 됩니다.
<script th:inline="javascript">
그럼 이 영역 안에서 자바스크립트와 타임리프를 같이 쓸 때 편한 기능을 제공해줍니다.
package hello.thymeleaf.basic;
import lombok.Data;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/basic")
public class BasicController {
...
@GetMapping("/javascript")
public String javascript(Model model) {
model.addAttribute("user", new User("UserA", 10));
addUsers(model);
return "basic/javascript";
}
...
}
<!DOCTYPE html>
<html xmlns:th="<http://www.thymeleaf.org>">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 자바스크립트 인라인 사용 전 -->
<script>
var username = [[${user.username}]];
var age = [[${user.age}]];
//자바스크립트 내추럴 템플릿
var username2 = /*[[${user.username}]]*/ "test username";
//객체
var user = [[${user}]];
</script>
<!-- 자바스크립트 인라인 사용 후 -->
<script th:inline="javascript">
var username = [[${user.username}]];
var age = [[${user.age}]];
//자바스크립트 내추럴 템플릿
var username2 = /*[[${user.username}]]*/ "test username";
//객체
var user = [[${user}]];
</script>
</body>
</html>
텍스트 렌더링
[[...]] 을 사용하면 타임리프가 알아서 랜더링을 해줍니다.
자바스크립트라서
<span th:text="${data}"></span>
같은 식으로 쓸 수 없습니다. 그래서 바로 값을 출력하는 [[...]] 문법을 써야합니다.
그래서 서버에서는 [[${user.username}]]
가 UserA로 변하는 랜더링이 끝나고 웹 브라우저가 자바스크립트를 실행할 때 자바스크립트 변수 username에 들어가게 됩니다.
실행 후 결과
var username = [[${user.username}]];
인라인 사용 전 -> var username = userA;
인라인 사용 후 -> var username = "userA";
인라인 사용 전 렌더링 결과를 보면 userA 라는 변수 이름이 그대로 남아있습니다.
UserA를 username 에 넣었습니다. 이렇게 되는게 맞습니다. [[${user.username}]]
가 UserA로 치환이 되기 때문입니다.
그런데 F12를 눌러서 보면 UserA is not defined 라고 뜹니다.
자바스크립트 문법이 안맞아서 깨지는 것입니다. 그래서 넣을 때 var username = “[[${user.username}]]”;
로 넣어줘야 문법 오류가 나지 않습니다.
타임리프 입장에서는 정확하게 렌더링 한 것이지만 아마 개발자가 기대한 것은 다음과 같은 "userA"라는 문자일 것입니다. 결과적으로 userA가 변수명으로 사용되어서 자바스크립트 오류가 발생합니다.
물론 다음으로 나오는 숫자 age의 경우에는 " 가 필요 없기 때문에 정상 렌더링 됩니다.
이처럼 자바스크립트에 타임리프의 어떤 값들을 전달하는게 쉽지 않습니다. 문자인 경우에는 개발자가 “를 매번 챙겨주는게 쉽지 않습니다.
인라인 사용 후 렌더링 결과를 보면 문자 타입인 경우 "를 포함 해줍니다.
추가로 자바스크립트에서 문제가 될 수 있는 문자가 포함되어 있으면 이스케이프 처리도 해줍니다.
예) " → \"
user”A” 라면 자동으로 user\”A\”로 처리해줍니다.
자바스크립트 내추럴 템플릿
타임리프는 HTML 파일을 직접 열어도 동작하는 내추럴 템플릿 기능을 제공합니다. 자바스크립트 인라인 기능을 사용하면 주석을 활용해서 이 기능을 사용할 수 있습니다.
실행 후 결과
var username2 = /*[[${user.username}]]*/ "test username";
인라인 사용 전 -> var username2 = /*userA*/ "test username";
인라인 사용 후 -> var username2 = "userA";
인라인 사용 전 결과를 보면 정말 순수하게 그대로 해석을 해버렸습니다. 따라서 내추럴 템플릿 기능이 동작하지 않고, 심지어 렌더링 내용이 주석처리 되어 버립니다.
콘솔에서 결과를 보면 username2에는 test username 이 들어가게 됩니다.
인라인 사용 후 결과를 보면 주석 부분이 제거되고, 기대한 "userA"가 정확하게 적용됩니다.
즉, "test username"
부분을 지우고 [[${user.username}]]
를 값으로 쓸 수 있게 해줍니다.
그래서 자바스크립트도 내추럴 템플릿이 가능해진 것입니다.
실제 HTML 파일을 실행시키면 "test username"
가 동작합니다. [[${user.username}]]
는 주석이기 때문이죠.
그런데 서버에서 랜더링이 되면 주석에 쓰였던 [[${user.username}]]
값이 들어갑니다.
객체
타임리프의 자바스크립트 인라인 기능을 사용하면 객체를 JSON으로 자동으로 변환해줍니다.
실행 후 결과
var user = [[${user}]];
인라인 사용 전 -> var user = BasicController.User(username=userA, age=10);
인라인 사용 후 -> var user = {"username":"userA","age":10};
인라인 사용 전은 객체의 toString()이 호출된 값입니다. 자바스크립트에 이 값을 넣어봤자 제대로 동작하지 않습니다.
인라인 사용 후는 객체를 JSON으로 변환해줍니다. 자바스크립트는 JSON을 그대로 넣을 수 있습니다.
<aside> 📖 [정리]
자바스크립트에선 항상 자바스크립트 인라인을 사용합시다!
</aside>