I'm trying to include a basic vanilla JS script into a Thymeleaf view but it seems to be completely ignored - I don't even see it when I inspect the page. I assume the issue is related with the fact that the view is part of a layout template but I cannot figure out where the problem is.
The View:
<!doctype html>
<html th:replace="~{fragments/layout :: layout(~{::title}, ~{}, ~{}, ~{::main})}">
<head>
<title>Reports Page</title>
</head>
<body>
<main role="main" class="flex-shrink-0">
<!-- some HTML code here -->
<select class="form-select" id="year" aria-label="Year dropdown" th:onchange="reloadPage()">
<option
th:each="yearRow : ${years}"
th:value="${yearRow}"
th:selected="(${yearRow} == ${year})"
th:text="${yearRow}">
</option>
</select>
<!-- other HTML code here -->
</main>
<script th:inline="javascript" type="text/javascript">
function reloadPage() {
alert("You selected a year");
}
</script>
</body>
</html>
The Layout fragment:
<!DOCTYPE html>
<html class="h-100" th:fragment="layout (title, css_assets, js_assets, content)" xmlns:th="http://www.thymeleaf.org">
<head>
<!-- Usual head stuff - meta tags, links to Bootstrap CSS & fonts libraries etc -->
<!-- Common CSS Styles -->
<link rel="stylesheet" th:href="@{/css/styles.css}">
<!-- Per-page placeholder for additional links -->
<th:block th:replace="${css_assets}" />
<title th:replace="${title}">Layout Title</title>
</head>
<body class="d-flex flex-column h-100">
<header th:replace="~{fragments/header :: header}"></header>
<div th:replace="${content}">
<p>Layout content</p>
</div>
<footer th:replace="~{fragments/footer :: footer}"></footer>
<!-- Common scripts -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<!-- Per-page placeholder for additional scripts -->
<th:block th:replace="${js_assets}" />
</body>
</html>
Inspecting the code, I don't see the inline script:
.. and in the console the Javascript function is not found:
Of course, probably I can use the ${js_assets} to inject my JS function from an external JS file but it bothers me why is it not working with the inline syntax. Am I missing something?
I'm pretty new to Spring Boot and Thymeleaf so please be understanding. Thanks!
Thanks to andrewJames I realized that the only HTML code that gets injected from my view into the final HTML is the one included between the main tags - everything else that is not a fragment in the layout is replaced. The easiest fix would have been to include my inline script inside main.
But since I want to have it right before the closing body tag I ended up leveraging the placeholder I already built into my layout for page-by-page JS.
Here's the new code for view (notice that the parameter for js_assets sent in the layout is pointing now to the fragment in the page)
<!doctype html>
<html th:replace="~{fragments/layout :: layout(~{::title}, ~{}, ~{::js_assets}, ~{::main})}">
<head>
<title>Reports Page</title>
</head>
<body>
<main role="main" class="flex-shrink-0">
<!-- some HTML code here -->
<select class="form-select" id="year" aria-label="Year dropdown" th:onchange="reloadPage()">
<option
th:each="yearRow : ${years}"
th:value="${yearRow}"
th:selected="(${yearRow} == ${year})"
th:text="${yearRow}">
</option>
</select>
<!-- other HTML code here -->
</main>
<th:block th:fragment="js_assets">
<script th:inline="javascript" type="text/javascript">
function reloadPage() {
alert("You selected a year");
}
</script>
</th:block>
</body>
</html>