Search code examples
htmlspringthymeleafspring-el

Bean preprocessor in fragment isn't processing my form object correctly


I've been working on a flexible pagination solution for my app, here's the fragment code:

<div th:fragment="pagination(form, postUrl)">
    <nav aria-label="Page Navigation">
        <ul class="pagination justify-content-center">
            <li class="page-item"
                th:classappend="${form?.page == 1} ? disabled : ''">
                <form th:action="@{${postUrl}}" th:object="${__${form}__}"
                    method="post">
                    <input hidden th:field="${form?.page}" th:value="${form?.page} - 1" />
                    <button class="page-link" th:text="#{page.previous}" />
                </form>
            </li>

            <div
                th:with="pageLimit=${form?.totalPages > 0} ? ${form?.totalPages} : 1">
                <li class="page-item"
                    th:each="i : ${#numbers.sequence(1, pageLimit)}">
                    <form th:action="@{${postUrl}}" th:object="${__${form}__}"
                        method="post">
                        <input hidden th:field="*{page}" th:value="${i}" />
                        <button class="page-link" style="border-radius: 0px"
                            th:text="${i}" />
                    </form>
                </li>
            </div>

            <li class="page-item">
                <form th:action="@{${postUrl}}" th:object="${__${form}__}"
                    method="post">
                    <input hidden th:field="*{page}" th:value="${form?.page} + 1" />
                    <button class="page-link" th:text="#{page.next}" />
                </form>
            </li>
        </ul>
    </nav>
</div>

and the fragment variables are passed in like this:

<div
    th:replace="fragments/pagination :: pagination(${objectForm}, '/my/url-is-here')">

However, on processing the view, I get this error (shortened for clarity):

Exception evaluating SpringEL expression: "my.object.ObjectForm@66bc4dd8" (template: "fragments/pagination" - line 6, col 37)
...
org.springframework.expression.spel.SpelParseException: EL1041E: After parsing a valid expression, there is still more data in the expression: 'bean_ref(@)'

It's most definitely something wrong with the bean preprocessing, because if I use the code as-is without fragments, __${form}__or th:with variables, it comes out OK. So does anyone know what's going on here?

Any insight would be appreciated!


Solution

  • So I worked on it some more, and it turns out I misunderstood how the Thymeleaf variables are being used. I believe it had something to do with th:field; changing it to name solved the issue.

    My understanding is that Thymeleaf variables are variables that have already been processed and do not need additional processing, which is why __${form}__ doesn't work.

    Furthermore, as I worked on this, I found out with the variable formVariables that you cannot just pass plaintext into a th attribute and expect it to work: it needs to be processed first, hence preprocessor.

    <div class="sticky-top paginator" th:fragment="pagination(form, postUrl, formVariables)">
            <nav aria-label="Page Navigation">
    
                <ul class="pagination justify-content-center">
                    <li class="page-item"
                        th:classappend="${form.page == 1} ? disabled : ''">
                        <form th:action="@{${postUrl}}" th:object="${form}" method="post">
    
                            <div th:include="__${formVariables}__"></div>
                            <input hidden name="page" th:value="${form.page - 1}" />
    
                            <button class="page-link" th:text="#{page.previous}" />
                        </form>
                    </li>
    
                    <th:block
                        th:with="pageLimit=${form.totalPages > 0} ? ${form?.totalPages} : 1">
                        <li th:each="i : ${#numbers.sequence(1, pageLimit)}"
                            class="page-item" th:classappend="${i == form.page} ? active : ''">
                            <form th:action="@{${postUrl}}" th:object="${form}" method="post">
    
                                <div th:include="__${formVariables}__"></div>
                                <input hidden name="page" th:value="${i}" />
    
                                <button class="page-link" style="border-radius: 0px"
                                    th:text="${i}" />
                            </form>
                        </li>
                    </th:block>
    
                    <li class="page-item"
                        th:classappend="${form.page >= form.totalPages} ? disabled : ''">
                        <form th:action="@{${postUrl}}" th:object="${form}" method="post">
    
                            <div th:include="__${formVariables}__"></div>
                            <input hidden name="page" th:value="${form.page + 1}" />
    
                            <button class="page-link" th:text="#{page.next}" />
                        </form>
                    </li>
    
                </ul>
    
    
            </nav>
    </div>
    
    

    I hope someone finds this useful!