Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Markup Selector Syntax ignores fragment contents #290

Open
moose56 opened this issue Apr 8, 2022 · 2 comments
Open

Markup Selector Syntax ignores fragment contents #290

moose56 opened this issue Apr 8, 2022 · 2 comments

Comments

@moose56
Copy link

moose56 commented Apr 8, 2022

Hi,

Spring boot version: 2.6.6
Java: 17

I am trying to write a controller action that returns multiple html elements based on a selector. This works when the items matching the selector are in the same template, but any matching elements that are in fragments included in the template are ignored.

Example:

Controller

@Controller
public class IndexController {
    @GetMapping("")
    public String showIndex() {
        return "index";
    }

    @GetMapping("reloadItems")
    public String reloadItems() {
        return "index :: %reload"; // <- only return elements with th:ref="reload" attribute
    }
}

index.html

<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div th:replace="header :: header"></div>

<p th:ref="reload">An Item to reload</p>
<p th:ref="reload">Another Item to reload</p>

<button>Reload</button>

<script src="webjars/jquery/3.6.0/jquery.min.js"></script>
<script>
    $("button").click(function () {
        $.get("reloadItems", function(data){
            console.log(data);
        }, "html");
    });
</script>
</body>
</html>

header.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div th:fragment="header">
        <p th:ref="reload">Header to reload</p>
    </div>
</body>
</html>

When the "Reload" button is clicked only <p>An Item to reload</p><p>Another Item to reload</p> are returned. The element in the header.html fragment is not.

If I move the element from header.html into index.html all elements are returned by the controller.

Is this expected behaviour? I would have expected the returned data to include the element from the included fragment.

I have attached a copy of my example Spring boot app.

thymeleaf-example.zip

@ultraq
Copy link
Member

ultraq commented Apr 11, 2022

I would say this is expected behaviour - the template/string value returned by Spring controller methods is used to locate which template to use as the basis for processing, and so it'll work with the template as it is in source instead of after the template after processing. The processing step occurs afterwards, which is when things like including other templates or fragments from other templates happens.

@moose56
Copy link
Author

moose56 commented Apr 11, 2022

Thank you for your reply.

This has come about as I am porting an old JSF application to Thymeleaf. The application makes use of partial page refreshes. You can specify multiple regions in the page to reload via a single Ajax call.

The Markup Selector Syntax seemed like a great way to achieve a similar thing as it can render out multiple selected elements of the page, however because it does not actually select from the "full" rendered template this does not work.

My workaround at the moment is to return the fully rendered page to the browser and pick out the items I want which is not optimal if the page contains a lot of additional information that I don't need to reload.

I find the current behaviour a little inconsistent based on:

@GetMapping("")
public String showIndex() {
    return "index";
}

returns the index.html template with all fragments included

@GetMapping("reloadItems")
public String reloadItems() {
    return "index :: %reload";
}

and this returns items specified within index.html, but ignores any included fragments.

Most use cases I have for this feature involve templates which include a fragment.

Is there a supported way in Thymeleaf of doing what I am trying to do?

If not is this a feature/behaviour that could be considered in the future?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants