onClick with Thymeleaf

Hi!

I’m having a little issue with handling onClick along with Thymeleaf.
I’ve tried a lot of different approaches to it, but they have caused a RefenceError, SyntaxError for ‘’ or given me an undefined value back for allNewsArticles.

This is my most recent attempt which has given med undefined in the console:

    data-th-onclick="@{displayFullArticle(this, `${allNewsArticles}`);}"

where this is what I pass in the controller:

        const model = {
            news: newsToBeDisplayed
            allNewsArticles: newsObjects
        };

        return {
            body: thymeleaf.render(view, model),
        };

Other attempts I’ve tried has been:

        data-th-onclick="@{displayFullArticle(this, '${allNewsArticles}');}"
        data-th-onclick="${'displayFullArticle(this, ' + allNewsArticles + ');'}"
        th:attr="onclick=|displayFullArticle(this, '${allNewsArticles }')|" 
        data-th-onclick="|displayFullArticle(this, '${allNewsArticles }')|"

I’ve ensured that allNewsArticles in fact does contain values.

Enonic version: 7.0.0-RC1
OS: Windows 10

What is displayFullArticle? Is it a method in one of your client-side Javascript assets? There are more intuitive ways to add on-click handlers, for example find element in DOM and apply event listener via addEventListener

It’s a function meant to display a detailed view of a news article almost covering the entire screen, like a popup sort of. The HTML doesn’t contain all the information, therefore I try to pass it to the function from the model in the controller

A safe syntax to do exactly what you want is probably something that uses normal concatenation and dereferencing, provided that allNewsArticles is already a String (not an Array, JavaScript Object or other data type):

data-th-onclick="'displayFullArticle(this, ' + ${allNewsArticles} + ')'"

But I’m guessing that the most likely problem you’re running into is that allNewsArticles is either an Array, a JSON-like JavaScript Object, or a List (appears as an Array in JavaScript, but Nashorn converts it to a List when passing it to the render() function in Thymeleaf).

More likely a working solution:

  1. Make sure allNewsArticles is a String. If Object, use JSON.stringify(), if it’s an Array-like, use Array.join() or similar…
  2. Create a variable in your JavaScript controller that contains the full attribute content:
    var onclickStr = 'displayFullArticle(this, ' + allNewsArticles + ')'
  3. and then data-th-onclick="${onclickStr}"

Let’s hope your future implementations won’t be as hacky as this. Try to keep as much logic as possible in the controller, or at least put it in client-side JavaScript assets if the controller is a no-go.

1 Like

What other solutions are there? I’ve ended up doing it like this due to the lack of knowledge about the controller in XP.

It doesn’t seem like I can access the object array the controller sends if it’s rendered in thymeleaf, nor if it’s sent in addition to the thymeleaf render. Also, I’ve gotten the impression that the data flows one way: from the controller to the model, and not back, which is what I feel like I need with this issue.

Is there something I’ve overlooked?

If you need data to flow both ways then you might look at setting up a service and communicate with it from the client via simple http requests: https://developer.enonic.com/docs/xp/stable/runtime/engines/http-service.

2 Likes

Another, more flexible (but less readable) way to pass controller parameters into Javascript inside a Thymeleaf template is this:

<script data-th-inline="javascript"">
/*<![CDATA[*/
    var allNewsArticles = /*[[${allNewsArticles}]]*/;
    console.log(allNewsArticles);
/*]]>*/
</script>
1 Like