Search code examples
javaspring-bootthymeleaf

Display multiple rows in Thymeleaf table


I'm trying to create a table of attendees of my event using Thymeleaf on a Spring Boot app.

My table looks like this:

<table class="table table-bordered tabl-striped">
    <thead class="thead-dark">
        <th>First Name</th>
        <th>Last Name</th>
    </thead>
    <tbody>
        <tr th:each="tempEvent : ${event}">
            <td th:text="${tempEvent.clubEventAttendees[event].firstName}" />
            <td th:text="${tempEvent.clubEventAttendees[event].lastName}" />
        </tr>
    </tbody>
</table>

If I just use a single td with <td th:text="${tempEvent.clubEventAttendees}" /> I get this:

[EventAttendees [id=1, firstName=Paul, lastName=Jones], EventAttendees [id=2, firstName=Luke, lastName=Smyth]

This output contains the correct data. The above table however only outputs my second attendee(Luke Smyth). If I change the td lines to:

<td th:text="${tempEvent.clubEventAttendees[0].firstName}" />
<td th:text="${tempEvent.clubEventAttendees[0].lastName}" />

or

<td th:text="${tempEvent.clubEventAttendees[1].firstName}" />
<td th:text="${tempEvent.clubEventAttendees[1].lastName}" />

The correct person is displayed depending on their position. How can I change my table to display any attendees that get returned?

This is my Event model:

@Entity
@Table(name="club_events")
public class Event {
    
    @OneToMany(mappedBy="clubEvent",
            cascade={CascadeType.PERSIST, CascadeType.MERGE,
                    CascadeType.DETACH, CascadeType.REFRESH,
                    CascadeType.REMOVE})
    private List<EventAttendees> clubEventAttendees;

    // define fiends
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private int id;
    
    @Column(name="name")
    private String name;
    
    @Column(name="location")
    private String location;
    
    @Column(name="description")
    private String description;
    
    @DateTimeFormat(pattern="yyyy-MM-dd")
    @Column(name="date_time")
    private LocalDate dateTime;
    
    public Event() {
        
    }

    public Event(int id, String name, String location, String description, LocalDate dateTime) {
        super();
        this.id = id;
        this.name = name;
        this.location = location;
        this.description = description;
        this.dateTime = dateTime;
    }
}

This is my EventAttendees model:

@Entity
@Table(name="club_event_attendees")
public class EventAttendees {
    
    @ManyToOne(cascade= {CascadeType.PERSIST, CascadeType.MERGE,
            CascadeType.DETACH, CascadeType.REFRESH})
    @JoinColumn(name="club_event_id")
    private Event clubEvent;

    // define fiends
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private int id;

    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;
    
    @Column(name="phone")
    private String phone;
    
    @Column(name="mobile")
    private String mobile;
    
    public EventAttendees() {
        
    }

    public EventAttendees(int id, String firstName, String lastName, String phone, String mobile, int clubEventId) {
        super();
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.phone = phone;
        this.mobile = mobile;
    }

}

Note: getters and setters have been removed.

I currently have a page which lists all events(in a table): enter image description here

The Attendees column will be removed once I get this figured out but if the View Attendees button is clicked I'd like to be taken to a page containing a similar table but with the firstName, lastName, phone and mobile of all attendees. Basically, I'd like to take the data returned in clubEventAttendees and display it in a table similar to the table above.


Solution

  • Okay so as promised, here is the code.

    I can explain the example with Person and Car. The idea is that Person has List<Car>.

    You can see Person details in the picture

    After pressing on View Cars, a new page is opened, where you see a list of Cars.

    Example of Car list

    How to achieve this is fairly simple. When rendering List<Person> from modelAttribute people, you can use the following code

    <tr th:each="person : ${people}">
                    <td th:text="${person.id}"></td>
                    <td th:text="${person.firstName}"></td>
                    <td th:text="${person.lastName}"></td>
                    <td>
                        <a th:href="@{'/person/' + ${person.id} + '/cars'}">View Cars</a>
                    </td>
    </tr>
    

    Href from th:href="@{'/person/' + ${person.id} + '/cars'}" executed following method in controller

    @GetMapping("/person/{personId}/cars")
    public String getCars(Model model, @PathVariable Integer personId){
        model.addAttribute("cars", carRepository.findAllByPersonId(personId));
        return "web/car-list";
    }
    

    after which a new template is rendered. I uploaded source code on GitHub, it can be found here https://github.com/Prebiusta/thymeleaf-playground

    Hope it helps, let me know if there is something else.