N per row with Thymeleaf

Recently I worked on an spring application that used the Thymeleaf template library to render HTML. The specific problem I faced was how to render an arbitrarily long list of items in a raster scanned manner with a given number of columns. So, for example, if the items were US cities and the column width was 5 I wanted to see something like this:

Here’s my template:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head lang="en">
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>Major US Cities</title>
    <link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css' />
    
    <style>
    	body {
    		font-family: 'Montserrat', sans-serif;
    	}
    	table {
    		border-collapse: collapse;
    		font-size: 150%;
    	}
    	td {
			width: 200px;
			height: 50px;
			text-align: center;
			vertical-align: middle;
		}
		tr:nth-child(odd) {
			background-color: #ccc;
		} 
    </style>
</head>
<body>

	<h1>Major US Cities</h1>

	<table>
	
		<tr th:each="city : ${cities}" th:if="${cityStat.index % width == 0}">
			<td th:each="index : ${#numbers.sequence(cityStat.index, cityStat.index + width - 1)}"
				th:if="${index lt cityStat.size}"
			    th:text="${cities[index]}">city</td>
		</tr>

	</table>

</body>
</html>

The money portion starts at line 33 with the th:each iteration attribute. This template is driven by a spring controller that sets the cities and width parameters.

package com.gosynaptic.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class ExampleController {
	
	private List<String> cities() throws IOException {
		List<String> list = new ArrayList<>();	
		try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("cities.txt"), "UTF-8"))) {
			String line;
			while ((line = br.readLine()) != null) {
				list.add(line.trim());
			}
		}
		return list;
	}
	
	@RequestMapping(value="/table", method={RequestMethod.GET, RequestMethod.POST})
	public ModelAndView table() throws IOException {
		ModelAndView mav = new ModelAndView("/cities");
		mav.addObject("cities", cities());
		mav.addObject("width", 5);
		return mav;
	}

}

If you have a better solution please post it in the comments! I’m making the minimal spring boot project available here for your convenience.

Posted in Technical | Comments Off