23

I'm at

http://example.com/some/page?p1=11

and I want to add a parameter to current url without having to redefine it:

http://example.com/some/page?p1=11&p2=32

with something like:

<a th:href="@{?(p2=32)}">Click here</a>

but the above code return http://example.com/some/page?&p2=32 (removes the p1 parameter).

How can I do it using Thymeleaf?

Andrea
  • 15,900
  • 18
  • 65
  • 84

6 Answers6

27

You can use URI builder, directly from Thymeleaf.

<span th:with="urlBuilder=${T(org.springframework.web.servlet.support.ServletUriComponentsBuilder).fromCurrentRequest()}"
      th:text="${urlBuilder.replaceQueryParam('p2', '32').toUriString()}">
</span>

For URL http://example.com/some/page?p1=11 prints out:

http://example.com/some/page?p1=11&p2=32

Explained:

  • SpEL T operator is used for accessing ServletUriComponentsBuilder type.
  • An instance created by factory method fromCurrentRequest is saved to urlBuilder variable.
  • A param is added or replaced in the query string by replaceQueryParam method, and then the URL is built.

Pros:

  • Safe solution.
  • No trailing ? in case of empty query string.
  • No extra bean in Spring context.

Cons:

  • It is quite verbose.

! Be aware that solution above creates one instance of the builder. This means that the builder cannot be reused because it still modifies an original URL. For multiple URLs on a page you have to create multiple builders, like this:

<span th:with="urlBuilder=${T(org.springframework.web.servlet.support.ServletUriComponentsBuilder)}">
    <span th:text="${urlBuilder.fromCurrentRequest().replaceQueryParam('p2', 'whatever').toUriString()}"></span>
    <span th:text="${urlBuilder.fromCurrentRequest().replaceQueryParam('p3', 'whatever').toUriString()}"></span>
    <span th:text="${urlBuilder.fromCurrentRequest().replaceQueryParam('p4', 'whatever').toUriString()}"></span>
</span>

For http://example.com/some/page prints:

http://example.com/some/page?p2=whatever 
http://example.com/some/page?p3=whatever     
http://example.com/some/page?p4=whatever
Václav Kužel
  • 1,070
  • 13
  • 16
19

The easiest solution is concatenating "requestURI" and "queryString". Here is example:

<div th:with="currentUrl=(${#httpServletRequest.requestURI + '?' + #strings.defaultString(#httpServletRequest.queryString, '')})">
   <a th:href="@{${currentUrl}(myparam=test)}">click here</a>
</div>

Result for "http://localhost:8080/some-page?param1=1":

 http://localhost:8080/some-page?param1=1&myparam=test

Result for "http://localhost:8080/some-page":

 http://localhost:8080/some-page?&myparam=test

Drawback:
Thymeleaf doesn't overwrite parameters - only adds parameters to URL. So if you user click once again to that URL, the result will be:

http://localhost:8080/some-page?param1=1&myparam=test&myparam=test

References:
http://forum.thymeleaf.org/How-to-link-to-current-page-and-exchange-parameter-td4024870.html

EDIT:

Here is some workaround, which removes parameter "myparam" from the URL:

<div th:with="currentUrl=(${@currentUrlWithoutParam.apply('myparam')})">
    <a th:href="@{${currentUrl}(myparam=test)}">click here</a>
</div>

Next in Spring configuration:

@Bean
public Function<String, String> currentUrlWithoutParam() {
    return param ->   ServletUriComponentsBuilder.fromCurrentRequest().replaceQueryParam(param).toUriString();
}

For more "global" solution, I would try extending processor for attribute "th:href" or creating my own attribute. I'm not a thymeleaf expert, just facing similar problem.

Raf
  • 325
  • 2
  • 9
  • Workaround for drawback is to create base url without parameter we want to add. – Raf Jan 27 '16 at 20:30
  • In the first case: be sure to use `${#httpServletRequest.requestURI + '?' + #strings.defaultString(#httpServletRequest.queryString, '')}` instead, in order to avoid appending `null` to your URL. – Priidu Neemre May 10 '16 at 14:09
  • 1
    Thanks for notice that "queryString" could be null. Link to [javadoc](https://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletRequest.html#getQueryString()). – Raf Jun 29 '16 at 11:54
3
th:href="@{/your/link?parameter=__${appendParameter}__}"
sndu
  • 933
  • 4
  • 14
  • 40
2

According to the docs you can specify all parameters

th:href="@{http://example.com/some/page(p1=11,p2=32)}"

You can use expressions to get values:

th:href="@{http://example.com/some/page(p1=11,p2=${someid})}"
Hans Kesting
  • 38,117
  • 9
  • 79
  • 111
0

This will work for you, even in Unicode:

 <ul class="pagination">
                <li th:if="${currentPage > 1}"><a th:href="'/search?key=' + ${param.key[0]} + '&amp;page=' +   ${currentPage-1}">Previous</a></li>

                      <li th:each="i : ${#numbers.sequence( 1, total+1)}" th:class="${i==currentPage}?active:''">
                            <a th:href="'/search?key=' + ${param.key[0]} + '&amp;page=' +   ${i}" th:inline="text">
                            [[${i}]] <span  class="sr-only">(current)</span>
                            </a>
                      </li>
                      <li><a th:if="${total + 1 > currentPage}" th:href="'/search?key=' + ${param.key[0]} + '&amp;page=' +   ${currentPage+1}">Next</a></li>
            </ul>
Lay Leangsros
  • 9,156
  • 7
  • 34
  • 39
0

Based on answer from Raf I ended up with this solution:

@Bean
public BiFunction<String, String, String> replaceOrAddParam() {
  return (paramName, newValue) -> ServletUriComponentsBuilder.fromCurrentRequest()
        .replaceQueryParam(paramName, newValue)
        .toUriString();
}
<a th:href="${@replaceOrAddParam.apply('myParamName', 'myNewValue')}">Text</a>
lu_ko
  • 4,055
  • 2
  • 26
  • 31