3

I would like to display the data I get from a search, personalized for my taste. At this moment, It is just plain text.

For example, I am searching for "Titanic", and I get the name, a few links, and some information from IMDB.

I have the following code:

search.html

<!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
    <title>Getting Started: Handling Form Submission</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Form</h1>
<form action="#" th:action="@{/search}" th:object="${search}" method="post">
    <p>Message: <input type="text" th:field="*{content}" /></p>
    <p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>

result.html

 <!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
    <title>Getting Started: Handling Form Submission</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Result</h1>
<p th:text="'content: ' + ${main.content}"></p>
<a href="/search">Submit another message</a>
</body>
</html>

SearchController.java

    @Controller
public class SearchController {
    @GetMapping("/search")
    public String greetingForm(Model model) {
        model.addAttribute("search", new Main());
        model.addAttribute("main", new Main().getContent());
        return "search";
    }

    @PostMapping("/search")
    public String greetingSubmit(@ModelAttribute Main main) {
        return "result";
    }
}

and Main.java

    private String content;
private List<Result> finalList;
private List<Result> resultList;

public void setContent(String content) throws IOException {
 //code to compute finalList
}

public List<Result> getContent() {
    return this.finalList;
}

The main problem is that I have no ideea where to being with. finalList is a list of objects of type "Result", which have fields such as

private List<String> link = new ArrayList<>();
private String name;
private TitleProp titleProp;

and TitleProp has

private String trailer;
private String rating;
private String description;
private String genre;

I would like to manipulate each field to show it on a different way, such as a table with more rows, etc. Any link or sample of code would help me a lot to understand Thymeleaf and Spring Boot more.

Kannon
  • 81
  • 3
  • 10
  • You will need to expose a couple of REST API Endpoints in one of your controllers, and then call them with Javascript from your front-end to make Ajax calls into your API. Once you have a response data object, you can use more Javascript to inject the data into your DOM in whatever way you see fit. All of this, the calls, responses, and content injection can be done without a page refresh. – SnakeDoc Jul 22 '20 at 20:42
  • So you mean, after I search for the information and I have “finalList” populated, I can expose some endpoints, such as “getName”, “getId”, etc.. (using “GetMapping”), and I can acces these by using Ajax calls? – Kannon Jul 22 '20 at 20:48
  • Pretty much. There's some great tutorials here: https://spring.io/guides/gs/consuming-rest-jquery/ and https://mkyong.com/spring-boot/spring-boot-ajax-example/ - They are both SpringBoot tutorials, but if you're only using raw Spring and Thymeleaf, you can probably adapt them slightly to fit your needs. – SnakeDoc Jul 22 '20 at 21:35
  • 1
    Thank you for the links, @SnakeDoc. I managed to solve this by learning JavaScript as much as I could in this time, and ajax. I posted an answer :). – Kannon Jul 24 '20 at 10:18

2 Answers2

1

I am coming with an answer to my question. I managed to get the result I wanted using Ajax, as SnakeDoc suggested. It was a long road, mostly because even if I had a working code, I spent a few hours searching for the Forbidden 403 error on ajax post request.

So, for the js part:

    function ajaxPost() {
        // Here we prepare data for the JSON
        var formData = {
            moviename: $("#moviename").val()
        }
        $.ajax({
            type: "POST",
            contentType: "application/json",
            url: "MYURL",
            data: JSON.stringify(formData),
            dataType: 'json',
            success: function (result) {
                {
                    $.each(result,
                        function (i, title) {
                            // do whatever you want with what you got from the server
                        });
                    console.log("Success: ", result);
                }
                console.log(result);
            },
            error: function (e) {
                console.log("ERROR: ", e);
            }

        });
    }

If this seems confusing, I access the fields you can see in my question by title.name, title.link, title.titleProp.description, etc, inside function (i, title)'s body. For the HTML,

        <label for="moviename" style="margin-right:5px">Title:</label>
        <input type="text" class="form-control" id="moviename" placeholder="Enter a title"/>

Where moviename is the variable name you get from the input.

Now, on the backend, we have to configure our path

    @PostMapping("/MYURL")
public ResponseEntity<Object> addSearch(@RequestBody SearchCriteria searchCriteria)
        throws IOException {
     // do whatever you want to get a result. I used a custom class "SearchCriteria"
     // which has a getter and a setter for the field
     // **private String moviename;**
    return ResponseEntity.ok(THIS GETS SENT TO AJAX);
}

The main problem was that I have web.security, and you have two choices. First one, you disabling csrf. You have to add this line to your security config.

    http.csrf().disable();

in protected void configure(HttpSecurity http) method.

Or, you add csrf to the ajax request. More info on this topic was discussed here

Kannon
  • 81
  • 3
  • 10
1

With thymeleaf, you can display a list in html like so:

<tr th:each="student: ${students}">
    <td th:text="${student.id}" />
    <td th:text="${student.name}" />
</tr>

More info: https://www.baeldung.com/thymeleaf-iteration

Epic Martijn
  • 335
  • 2
  • 12
  • But when I get the information from the backend, by using Thymeleaf don’t I get only strings, not objects? – Kannon Jul 24 '20 at 11:10
  • 1
    You use @ModelAttribute to pass your model to the template renderer. th:each then loops over the object that is passed to it, and generates the html that is sent in the response. If you do it with an asynchronous request, your remark is true, but, as thymeleaf evaluates the expressions before the response is sent back to the browser, it has access to the objects you pass to it. – Epic Martijn Jul 24 '20 at 11:35
  • Oh, that’s great. Cool to know that Thymeleaf can do that. Thank you for the answer and clarification! – Kannon Jul 24 '20 at 11:52
  • I recently made a spring/thymeleaf website for a school project. I think it might be useful for you (so you can copy paste some code if you'd like ;) ). https://github.com/martijnmeeldijk/taskmanager-martijn – Epic Martijn Jul 24 '20 at 12:32
  • Thank you! For the backend part, I don’t have any problems, the problem was that I never connected backend and frontend, and had no prior knowledge on JavaScript. I will not copy paste, this way I learn the hard way, and I recommend this to anyone! – Kannon Jul 24 '20 at 12:36