Home > Software engineering >  Update content in Thymeleaf without reloading whole page
Update content in Thymeleaf without reloading whole page

Time:12-04

i want to update the content of div "output" without reloading the whold page. When the user inputs something and hits the run button, the server will output the evaluation on the div "output". But the following code puts only div "output" on the browser. The other piece of page is gone. what i have done wrong ?

<body>
    <div >
        <div th:insert="fragments/body :: navigation (true, ${spieler.name}, ${spieler.punkte}, ${spieler.level})"></div>
    
        <div >
            <label  id="thetext">Du liebst Abenteuer und möchte endlich reisen.<br>
                Du hast ein bisschen Geld und das reicht für ein Ticket zur nächsten Insel.<br>
                Unglücklicherweise ist dein Schiff in einem Sturm gesunken. <br>
                Du hat glück, an einen Strand zu landen. <br><br>
                Jetzt musst du die Herausforderungen mit deinen SQL-Kenntnissen meistern.<br>
                Je schneller du die Probleme löst, desto besser ist dein Ranking.<br><br>
                Viel Spaß !!!<br>
            </label>
        </div>
    
        <div >
            <input id="startButton" onclick="nachsteFrage()" 
                   type="button" value="Weiter">
        </div>
    
        <form method="post"  th:action="@{/level1-answer}" th:object="${answer}">
            <div >
                <input type="text"  id="codeArea" name="antwort" th:field = "*{SQL}"
                          rows="3" placeholder="Hier steht dein Code ...">
                <br>
                <div >
                    <button onclick="updateOutput()" 
                             id="ausfuehrenBtn">run</button>
                </div>
            </div>
        </form>
        <div id="output" style="overflow:scroll; height:400px;">
             <span th:text = "${evaluation}"></>
        </div>
    
    </div>
    
    <script th:inline="javascript">
        function updateOutput() {
            $.get("output").done(function(fragment) { 
                $("#output").replaceWith(fragment);
            });
        }
    </script>
</body>

the controller

@RequestMapping(value="/level1-answer", method=RequestMethod.POST)
public String postSQL (Model map, @ModelAttribute("answer") Answer answer) {
    map.addAttribute("evaluation",answer.getSQL()   "  this is correct or incorrect"); 
    return "level1 :: #output";
}

the html file is in templates/level1.html

CodePudding user response:

Here is a very basic demo, to show one approach.

I start with the main web page testajax.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>Test Ajax Fragment</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    </head>
    <body>
        <h3>A Permanent Heading</h3>
        <div id="output">
            Some initial text displayed here. This will be replaced.
        </div>
        <br>
        <button onclick="updateOutput()" 
                id="ausfuehrenBtn">run</button>
        <script>
            function updateOutput() {
                $.post("test_ajax_frag").done(function (fragment) {
                    console.log(fragment);
                    $("#output").replaceWith(fragment);
                });
            }
        </script>
    </body>
</html>

Note that there is no <form> here, because we are not going to be submitting any form data - we will, instead, be using an Ajax request, later on.

The controller used to display this page:

@RequestMapping(value="/test_ajax", method=RequestMethod.GET)
public String sendHtml(Model map) {
    //map.addAttribute("foo", "bar");
    return "testajax";
}

It's a simple GET handler, used to display the initial page. I don't even have any specific Model data in this case, just to keep the demo simple.

The Thymeleaf fragment template is testajaxfragment.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <body>
        <div th:fragment="test_frag">
            <div id="output">
                Some replacement content.
            </div>
        </div>
    </body>
</html>

The main page contains an Ajax call, which is executed when the button is clicked:

$.post("test_ajax_frag")

We need a separate controller for that:

@RequestMapping(value="/test_ajax_frag", method=RequestMethod.POST)
public String sendHtmlFragment(Model map) {
    //map.addAttribute("foo", "bar");
    return "testajaxfragment :: test_frag";
}

In this case, I chose to use a POST request in the Ajax call - so the controller has to also be a POST handler.

When the controller runs, it returns a fragment of HTML to the JavaScript function which called it. That function then replaces the output div:

$("#output").replaceWith(fragment);

This is a fairly crude approach, but shows the technique you are asking about in the question and in your comments.

  • Related