11

I'm trying to write some Javascript code where I need to use a model attribute. Here is how I define the script tag:

<script type="text/javascript" th:inline="javascript">
    /*<![CDATA[*/

    //need some loops

    /*]]>*/
</script>

What I need to do is, using each iterations over model attributes inside the script. So far I couldn't manage to do this with th:each. Any help is appreciated.

4
  • @sgpalit Assume it contains a list of strings. I need to iterate over the String list and map each string to another. Commented Apr 22, 2015 at 13:51
  • Do you use the JSP? Commented Apr 22, 2015 at 13:56
  • I'm using Thymeleaf. Commented Apr 22, 2015 at 13:56
  • Do you try parse your model to a JSON object? and use Thymeleaf to iterate. I am not familar with Thymeleaf. Commented Apr 22, 2015 at 13:59

6 Answers 6

24

I guess you need to wrap your model attrubite in double brackets, like this: [[${modelAttribute}]]. The script inlining section of the Thymeleaf docs can help a bit: http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#script-inlining-javascript-and-dart

<script type="text/javascript" th:inline="javascript">
    /*<![CDATA[*/

    var theList = [[${modelAttribute}]]
    for (i = 0; i < theList.length; i++) {
        doSomething(theList[i]);
    }

    /*]]>*/
</script>
Sign up to request clarification or add additional context in comments.

1 Comment

So if you have a lot of elements in the list and the class representing an element contains a lot of members you end up with a huge chunk of JavaScript even if you just need to retrieve only 1 property... That also sucks if there are sensitive properties in your element, they'll show up in JavaScript. Is there a better way to loop through the list and hold the current element in a local Thymeleaf variable like with JSP/JSTL?
18

You can also do like this, which is the most compact I guess:

In your @Controller:

model.addAttribute("items", new String[] { "item1", "item2", "item3" });

In your template:

<script type="text/javascript" th:inline="javascript">

var items = [];

/*[# th:each="n : ${items}"]*/

items.push("[(${n})]");

/*[/]*/

</script>

Other useful stuff is explained here: [MAJOR FEAT] New syntax for textual template modes #395

1 Comment

Thanks for flagging this up - I've failed to get the th:each working inline, but I'm sure that's my novicey use of Thymeleaf. It's a good feature and would remove @maxime's worries in the accepted answer.
4

Thymeleaf 3 -> see yglodt answer

if you're stuck with Thymeleaf 2 and your model attribute is complex (like the case of Maxime Laval), I ended up looping over a script :

<script th:inline="javascript">
  var dataLayer = [];
</script>
<script th:each="item:${items}" th:inline="javascript">
  dataLayer.push({'attr1':item.attr1, 'attr2':item.attr2, 'attr3':item.attr3});
</script>
<script th:inline="javascript">
  console.log(dataLayer); // do whatever you want with dataLayer...
</script>

Not very nice but I couldn't find better for my Google analytics.

Comments

1

This works with me in latest version of thymeleaf by adding /*[[${name}]]*/

<script type="text/javascript" th:inline="javascript">
    /*<![CDATA[*/

    var theList = /*[[${modelAttribute}]]*/
    for (i = 0; i < theList.length; i++) {
        doSomething(theList[i]);
    }

    /*]]>*/
</script>

Comments

1

Another approach if you are stuck with Thymeleaf 2 is absusing the "th:block"-Element within your Script-Tag

<script type="text/javascript">
        var arrayOfIds= [
        <th:block th:each="element: ${list}" th:inline="text">[[${element.Id}]],</th:block>
            -1 
        ];
        arrayOfIds.pop(); // Remove the superflous last Element
    </script>

Comments

1

thymeleaf converts object into javascript variable within the script tag, so can access properties using javascript codes. no need to worry about th:

     <script type="text/javascript" th:inline="javascript">
                            /*<![CDATA[*/
                            //the list converts as a javascript object
                            var availableTypes = /*[[${dataList}]]*/;
                            console.log(availableTypes);
                            /*]]>*/
     </script>

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.