Lab 2: Using Spring ViewComponent
This lab aims to build the same application as Lab 1. But this time we will use Spring ViewComponent and htmx-spring-boot to delegate rendering responsibility to the ViewComponent.
An Introduction to Spring ViewComponent
A ViewComponent is a Spring-managed bean that defines a rendering context for a corresponding template, this context is called ViewContext.
We can create a ViewComponent by annotating a class with the @ViewComponent annotation and defining a public nested record that implements the ViewContext interface.
@ViewComponent
public class SimpleViewComponent {
public record SimpleViewContext(String helloWorld) implements ViewContext {
}
public SimpleView render() {
return new SimpleView("Hello World");
}
}A ViewComponent needs to have a template with the same name defined in the same package. In the template, we can access the properties of the record.
@param SimpleViewComponent.SimpleViewContext simpleViewContext
<div>${simpleViewContext.helloWorld()}</div>Creating the UserMangement with Spring ViewComponent
To start we need to add three dependencies to the build.gradle.kts file.
We can enable live-reload for Spring ViewComponent with these properties in application.yaml.
Also, remove the gg.jte properties and uncomment the spring.view-component properties
We start by creating a UserManagementComponent.java file in the de.tschuehly.easy.spring.auth.user.management package.
We then create a UserManagementComponent.jte template in the de.tschuehly.easy.spring.auth.user.management package:
We add a static import to the UserManagementComponent class.
The param is a UserManagementContext as we put all variables into this record.
Now we will create a separate component for the table.
UserTableComponent
Create a UserTableComponent.java in de.tschuehly.easy.spring.auth.user.management.table
In the last lab, we defined the USER_TABLE_BODY_ID in the UserController.java. Now define it in the UserTableComponent.java .
Now we will create a UserManagementComponent.jte template in the same package as the UserTableComponent.java:
We then create a UserRowComponent.java class in de.tschuehly.easy.spring.auth.user.management.table.row package:
We then create a UserRowComponent.jte template in the auth.user.management.table.row package.
(1): We use the userRowContext.easyUser() attribute to access the user we want to render.
(2): We set the id of the table row using the UserRowContext.htmlUserId(uuid) function
UserTableComponent
We now change the UserTableComponent.java:
(1): We autowire the userRowComponent.
(2): We add a List<ViewContext> property to the UserTableContext
(3): We call the userService.findAll() method
(4): Then we call the autowired userRowComponent::render method in the .stream().map() function.
Now we will render the userTableRowList in the UserTableComponent.jte:
(1): We loop through the userTableRowList and create a row loop variable.
(2): We render the row ViewContext in the <tbody>
Now we can render the table using Spring ViewComponent in the UserMangement.java:
(1): We autowire the UserTableComponent
(2): We add a userTable ViewContext field to the UserManagementContext
(3): In the UserManagementComponent.render method we call the userTableComponent.render and pass it into the UserManagementContext constructor.
In the UserManagementComponent.jte template, we can insert the rendered table:
In the UserController.java we can autowire the UserManagementComponent ViewComponent and render it in the index method:
We can restart the application, navigate to http://localhost:8080/ and see the table rendered.

Lab 2 Checkpoint 1
If you are stuck you can resume at this checkpoint with:
git checkout tags/lab-2-checkpoint-1 -b lab-2-c1
Edit User
We now create the edit user functionality with Spring ViewComponent.
We create an EditUserComponent.java in the de.tschuehly.easy.spring.auth.user.management.edit package:
(1): We first autowire the userService in the constructor
(2): Then we create a render method with a uuid parameter.
(3): We get the user with the userService.findById(uuid) method
(4): We add the uuid, username and password of the user to the EditUserContext ViewContext
We then create the EditUserComponent.jte template in the same package as the EditUserComponent.java
In the UserController.java we remove the UserForm record, autowire the EditUserComponent and then change the editUserModal method to call the editUserComponent.render method.
We can restart the application navigate to http://localhost:8080/ and the edit user modal works again.

Lab 2 Checkpoint 2
If you are stuck you can resume at this checkpoint with:
git checkout tags/lab-2-checkpoint-2 -b lab-2-c2
Fix the Save User functionality
In Lab1 we used HX Response headers to set the swapping functionality directly in the UserController.java:
We now want to move this functionality to the UserRowComponent.
HtmxUtil
I have already created a HtmxUtil class in the de.tschuehly.easy.spring.auth.htmx package that helps us set the HX Response Headers.
We are using Wim Deblauwes htmx-spring-boot library: github.com/wimdeblauwe/htmx-spring-boot. It offers a HtmxResponseHeader enum with all possible values and a HxSwapType enum.
We will add these convenience methods to the HtmxUtil.java class:
Back to the UserRowComponent we create a rerender function where we use these utility functions:
(1): We retarget to the id of the <tr> element we created with the UserRowContext.htmlUserId() function.
(2): We swap the outerHTML of the target element
(3). And we trigger the CLOSE_MODAL_EVENT
(4): Finally, we return the UserRowContext with the easyUser
In the UserController.saveUser method we can call the userRowComponent.rerender method
We can restart the application and navigate to http://localhost:8080/ and the save user function works again!
Lab 2 Checkpoint 3
If you are stuck you can resume at this checkpoint with:
git checkout tags/lab-2-checkpoint-3 -b lab-2-c3
We have the advantage that the Controller doesn't need to know how the UserRowComponent template looks and what needs to be swapped. The UserRowComponent offers an API to rerender a row.
Create User
Finally, we need to migrate the create user functionality to Spring ViewComponent.
We start by creating a CreateUserComponent in the de.tschuehly.easy.spring.auth.user.management.create package:
We now need to create a CreateUserComponent.jte in the same package as the CreateUserComponent.java
We can now call the createUserComponent.render method in the UserController.getCreateUserModal method:
We can restart the application and navigate to http://localhost:8080/ and the create user modal is shown when we click on Create User

Finally, we need to migrate the UserController.createUser method.
Currently, it looks like this:
As before we want to move this code into the UserRowComponent.java, by creating a new renderNewRow function:
We can now simplify the UserController.createUser function:
Now if we restart the application we can save a new user and they are inserted at the start of the table.

Lab 2 Checkpoint 4
If you are stuck you can resume at this checkpoint with:
git checkout tags/lab-2-checkpoint-4 -b lab-2-c4
Last updated