Home > Software design >  How can I input HTML from JS function into Thymeleaf th:text?
How can I input HTML from JS function into Thymeleaf th:text?

Time:11-14

I want to show rating based on the returned value of an object method. JS function - returns an html that contains amount of stars based on a parameter. Parameter - digit up to 5. I get it from calling employee.getUser().getAvgGrade().

Here is a table I have

            <table>
            <thead>
            <tr>
                <th>Name</th>
                <th>Rating</th>
                <th>Schedule</th>
            </tr>
            </thead>
<tbody>
    <tr th:each="employee:${employees}">

        <td th:text="${employee.getUser().getFullName()}"></td>
        <td th:text="${employee.getUser().getAvgGrade()}"></td>
        <td th:text="${employee.getTimeBegin()   ' - '   employee.getTimeEnd()}"></td>

    </tr>
    </tbody>
        </table>

Here is a JS function that returns HTML

    function star(rate) {
    var starHTML = '';
    var rate = parseInt(rate);
    var increment = 0;
    var max = 5;

    while(increment < rate) {
        starHTML  = '<i >grade</i>';
        increment  ;
    }

    while(max > rate) {
        starHTML  = '<i >grade</i>';
        max--;
    }
    return starHTML;
};

CSS for stars

<link href="https://fonts.googleapis.com/icon?family=Material Icons"
      rel="stylesheet">

I want to call this function with the integer from getAvgGrade() ( second th:text ) and place the html it returns as th:text ( so the cell holds the stars ).

CodePudding user response:

You can simplify this by using Thymeleaf to manage generating the stars, instead of using JavaScript.

Here is that approach:

First, some Java test data (a simplified version of your data, just for this demo):

List<UserRating> userRatings = new ArrayList<>();
userRatings.add(new UserRating("Abel", 2));
userRatings.add(new UserRating("Baker", 3));
userRatings.add(new UserRating("Charlie", 4));

So, we have 3 users with grades of 2, 3, and 4.

The Thymeleaf template is as follows:

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Avg Grade</th>
            <th>Stars</th>
        </tr>
    </thead>
    <tbody>
        <tr th:each="user : ${users}">
            <td th:text="${user.name}"></td>
            <td th:text="${user.grade}"></td>
            <td>
                <th:block th:each="star,iterStat : ${#numbers.sequence(1,5)}">
                    <span th:if="${user.grade} >= ${iterStat.count}" 
                          class="material-icons" 
                          style="color: orange;">grade</span>
                    <span th:if="${user.grade} < ${iterStat.count}" 
                          class="material-icons" 
                          style="color: grey;">grade</span>
                </th:block>
            </td>
        </tr>
    </tbody>
</table>

The result of applying the test data to the template is this:

enter image description here

Notes

This approach does not require any JavaScript.

I assumed the average grades are integers, but this also works for decimal values.

To build 5 stars I use a predefined sequence counting from 1 to 5:

${#numbers.sequence(1,5)}

I use an iteration status variable called iterStat to track progress through this sequence of 5 integers.

I compare this iterStat.count value (the current position in the iteration) with the average grade value. I use this to determine if the star should be orange or grey.

The th:block element is a special Thymeleaf element. It can be convenient to use in certain iteration situations. More details here.


You can certainly implement this in other ways - for example, by calling a JavaScript function after the table has been drawn - but that would involve more JavaScript code - your function, plus extra code to iterate the table values in JavaScript.

I would recommend the above approach instead. But I understand, if that may not be what you want, or if it may not fit into your overall approach for some reason.

  • Related