admin管理员组

文章数量:1310498

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 class="container mx-auto">
        <div th:insert="fragments/body :: navigation (true, ${spieler.name}, ${spieler.punkte}, ${spieler.level})"></div>
    
        <div class="d-flex justify-content-center">
            <label class="text-center mt-4" 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 class="d-flex justify-content-center">
            <input id="startButton" onclick="nachsteFrage()" class="btn-secondary mt-4"
                   type="button" value="Weiter">
        </div>
    
        <form method="post"  th:action="@{/level1-answer}" th:object="${answer}">
            <div class="form-group">
                <input type="text" class="form-control mt-4" id="codeArea" name="antwort" th:field = "*{SQL}"
                          rows="3" placeholder="Hier steht dein Code ...">
                <br>
                <div class="d-flex justify-content-center">
                    <button onclick="updateOutput()" class="btn-secondary mt-4"
                             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

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 class="container mx-auto">
        <div th:insert="fragments/body :: navigation (true, ${spieler.name}, ${spieler.punkte}, ${spieler.level})"></div>
    
        <div class="d-flex justify-content-center">
            <label class="text-center mt-4" 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 class="d-flex justify-content-center">
            <input id="startButton" onclick="nachsteFrage()" class="btn-secondary mt-4"
                   type="button" value="Weiter">
        </div>
    
        <form method="post"  th:action="@{/level1-answer}" th:object="${answer}">
            <div class="form-group">
                <input type="text" class="form-control mt-4" id="codeArea" name="antwort" th:field = "*{SQL}"
                          rows="3" placeholder="Hier steht dein Code ...">
                <br>
                <div class="d-flex justify-content-center">
                    <button onclick="updateOutput()" class="btn-secondary mt-4"
                             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

Share Improve this question asked Dec 2, 2021 at 15:19 CT11CT11 731 silver badge7 bronze badges 5
  • Your ausfuehrenBtn button is currently placed inside the <form> - and therefore when you click it, the form submission logic will be executed: method="post" action="/level1-answer". The updateOutput() function (which is a GET not a POST) will not be called at all. You can see this for yourself by moving the button to after the closing </form> tag. The GET in the function may still fail if you do not have a controller for it. Basically: don't mix form-based actions with Ajax actions, like this. – andrewJames Commented Dec 2, 2021 at 19:57
  • Minor point: The span element is missing a proper closing tag: <span th:text="${evaluation}"></span>. – andrewJames Commented Dec 2, 2021 at 19:57
  • If you want to do this, check out htmx as it is build for doing this kind of thing. I have a few articles on my website to get you started with htmx and Thymeleaf if you are interested: wimdeblauwe./tags/htmx – Wim Deblauwe Commented Dec 3, 2021 at 7:37
  • @andrewJames how can i solve this problem please ? Sorry, i'm new in Spring – CT11 Commented Dec 3, 2021 at 8:53
  • It's not really a Spring question - it's a HTML forms vs. Ajax question. You have all the pieces you need in your question, but you have just mixed together two separate approaches. I have tried to show an example which focuses on the Ajax approach - see my answer. – andrewJames Commented Dec 3, 2021 at 15:09
Add a ment  | 

2 Answers 2

Reset to default 7

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">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-patible" content="ie=edge">
        <title>Test Ajax Fragment</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://code.jquery./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">
    <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 ments.

this works for me

        <script>
            $(document).ready(function () {

                //call function when page is loaded
                getContent();

                //set on change listener
                $('#selection').change(getContent);

                function getContent() {

                    //create url to request fragment
                    var url = /content/;
                    if ($('#selection').val() === "Content 1") {
                        url = url + "content1";
                    } else {
                        url = url + "content2";
                    }

                    //load fragment and replace content
                    $('#replace_div').load(url);
                }
            })
        </script>

https://riptutorial./thymeleaf/example/28530/replacing-fragments-with-ajax

本文标签: javascriptUpdate content in Thymeleaf without reloading whole pageStack Overflow