0

I am very new to coding in general, and have been learning Java. We've started to learn Spring Boot and Thymeleaf, and we have to work on an app where we search for jobs using keywords. I've created a handler to be able to search for the jobs and add them to an ArrayList of a HashMap, and have a template that displays those results. However, my issue is we're supposed to display the number of results each time at the top of the page, and I cannot figure out how to do that.

I've tried using .size, #lists, #maps, th:size, everything I can think of. Nothing is working. I've tried putting it above the table, in the table, between the loops, everything. The closest I've gotten is just printing the word "Results" at the top of the page. I've been reading Thymeleaf tutorials, looking at Baeldung, googling for days. I very much appreciate any assistance!

@RequestMapping(value = "results")
public String search(
    Model model,
    @RequestParam String searchType,
    @RequestParam String searchTerm
) {
    ArrayList<HashMap<String, String>> results =
            JobData.findByColumnAndValue(searchType, searchTerm);
    model.addAttribute("columns", ListController.columnChoices);
    model.addAttribute("results", results);
    return "search";
}

And Thymeleaf:

<hr />
<!--<span th:text="${results.size}">Result</span> -->
<!--<span th:text="${#lists.size(job.results)}">Result(s)</span> -->
<!-- <td th:text="${#lists.size(job.results)}">Result(s)</td> -->

<!-- TODO #2 - Loop over jobs map to display all job fields -->
<!--<div th:fragment="div"> -->

<table  class="job-listing" th:each="job : ${results}">
    <tr th:each="row : ${job}">
        <!--<td th:text="${results.size}"></td>-->
        <td th:text="${row.key}"></td>
        <td th:text="${row.value}"></td>
    </tr>
</table>
</div>
<!--    </table>-->
<!--</div> -->
</body>
</html>

I've included my handler method, and the code from the template I'm working with. Sorry about all the comments - I'm trying to keep track of what I've tried.

Edit: This is now my template code that prints the word "Result(s)" only after I do a search (which I want). My issue now is I still can't get it to print the number of results.

<span th:if="${results} and ${results.size()}">
    <h3>Result(s)</h3>
</span>

<table  class="job-listing" th:each="job : ${results}">
    <tr th:each="row : ${job}">
        <td th:text="${row.key}"></td>
        <td th:text="${row.value}"></td>
    </tr>
</table>

2 Answers2

1

Use list.size() or map.size() to get the size in your template:

For example:

<td th:text="${results.size()}"></td>
<td th:text="${job.size()}"></td>

To check the size in th:if just use this:

<div th:if="${results.size() > 0}">
    ...
</div>

Or this:

<div th:if="${!results.isEmpty()}">
    ...
</div>
Samuel Philipp
  • 10,631
  • 12
  • 36
  • 56
  • When I do this within my table, it prints the number of results, but multiple times - with every job and inside the table, instead of just at the top of the page. I've now added my template code above that shows I'm able to get it to print the word "Result(s)" out only after I do a search (which is what I want), but I still can't get it to print the number of results with the word. – picturecharity Jun 30 '19 at 05:25
  • @picturecharity just use this condition `${results.size() > 0}`.I updated my answer according to that. – Samuel Philipp Jun 30 '19 at 13:29
  • That worked! I did

    Thank you so very much for your help!
    – picturecharity Jun 30 '19 at 16:43
0

Your query here is highly suspect:

ArrayList<HashMap<String, String>> results =
        JobData.findByColumnAndValue(searchType, searchTerm);

First, you are calling a service statically. This is likely not what you want to do. Read up on static methods.

Second, your query is returning a List of a Map. This is likely too complex for a simple query. I would highly suggest providing a simple List to the model. You are likely looking at printing results.size.size in your page to get what you want, but I wouldn't recommend this approach.

One way to make this clearer would be to do something like:

List<JobListing> jobListings =
        jobDataService.findByColumnAndValue(searchType, searchTerm);
model.addAttribute("jobListings", jobListings);

Your new JobListing bean would have the properties of a job listing. Take a look at Project Lombok to make your life a little easier with beans if your project will allow an additional dependency. In particular, look at @Data and @Builder.

Take a look at constructor-injection for your jobDataService. Injecting your services allows your code to be far more adaptable as your application grows.

Then you would simply have:

Results Found: <span th:text="${#lists.size(jobListings)}" remove="tag">[0]</span>

<table class="job-listing">
    <tr th:each="jobListing : ${jobListings}">
        <td th:text="${jobListing.id}">[Id]</td>
        <td th:text="${jobListing.createdOn}">[Creation Date]</td>
        <!-- or whatever your requirements dictate -->
    </tr>
</table>

Note that you would be creating a new <table> on each iteration in your original HTML as well. I doubt this what you'd want.

Printing the size of a list can be found here.

The main tip that I would also have is to write your code for the next programmer to read it. Use logical variable names and keep things simple. It's a long road - hang in there.

riddle_me_this
  • 8,575
  • 10
  • 55
  • 80
  • I appreciate the comments. This is an assignment, and a lot of the code was already written for us, including the ArrayList of a HashMap, so we can't change it. I now have my code in my html template with a loop, using th:if so that it prints the word "Result(s)" to the screen only after I do a search (which is what I want), but I still can't get it to print the number of results (I've now added that code above) – picturecharity Jun 30 '19 at 05:13