0

I have the following db table:

CREATE TABLE authors
    (
        id         INT AUTO_INCREMENT PRIMARY KEY,
        authorName VARCHAR(250) NOT NULL
    );

I want to print our the authors as follows:

A

  • Anselma McKennan

B

  • Berty Gandley
  • Bette-ann Askem

C

  • Clerc Djakovic
  • Cristie Isacsson

D

  • Dannie Glidder
  • Darcey Rohmer
  • Dom Robuchon

Currently I have by thymleaf template printing as follows and I do not want to print out the Alphabet LETTER each time in front of the author:

A

  • Anselma McKennan

B

  • Berty Gandley

B

  • Bette-ann Askem

C

  • Clerc Djakovic

C

  • Cristie Isacsson

D

  • Dannie Glidder

D

  • Darcey Rohmer

D

  • Dom Robuchon

My controller:

@GetMapping("/index.html")
    public String mainPage(Model model) {
        model.addAttribute("authorsData", bookService.getAuthorData());
        return "/authors/index";
    }

My service:

public List<Author> getAuthorData() {
    List<Author> authors = jdbcTemplate.query("SELECT id, authorName from authors ORDER BY authorName", (ResultSet rs, int rowNum) -> {
        Author author = new Author();
        author.setId(rs.getInt("id"));
        author.setAuthorName(rs.getString("authorName"));
        return author;
    });
    return new ArrayList<>(authors);
}

My Thymeleaf code is as follows:

<div class="Authors-block" th:each="author : ${authorsData}" >
  <h2 class="Authors-title" id="a" th:text="${author.getAuthorName().charAt(0)}">
  </h2>
  <div class="Authors-letter">
    <div class="Authors-item"><a href="/authors/slug.html" th:text="${author.getAuthorName()}"></a>
    </div>
matua
  • 597
  • 4
  • 12

2 Answers2

1

Make your getAuthorData() return Map<Character, List> where key is letter and value are authors starting with that letter

public List<Author> getAuthorData() {
    List<Author> authors = jdbcTemplate.query("SELECT id, authorName from authors ORDER BY 
    authorName", (ResultSet rs, int rowNum) -> {
        Author author = new Author();
        author.setId(rs.getInt("id"));
        author.setAuthorName(rs.getString("authorName"));
        return author;
    });
    return authors.stream()
       .collect(
          Collectors.groupingBy(
             author -> author.getAuthorName().charAt(0)
          )
       );
}

In html you can iterate through map entries like here: How to loop through Map in Thymeleaf just notice that as a value you will have iterable array

Krzysztof K
  • 736
  • 4
  • 19
0

You can do with collection selection as well. Something like this for example:

<div class="Authors-block"
     th:each="letter : ${ {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'} }"
     th:with="authors=${authorsData.?[authorName.startsWith(#root.letter)]}"
     th:unless="${authorsData.?[authorName.startsWith(#root.letter)].empty}"
     >
  <h2 class="Authors-title" id="a" th:text="${letter}" />
  <div class="Authors-letter">
    <div class="Authors-item" th:each="author: ${authors}"><a href="/authors/slug.html" th:text="${author.getAuthorName()}"></a>
    </div>
  </div>
</div>

But I don't know if I'd recommend it.

Metroids
  • 18,999
  • 4
  • 41
  • 52