user7875786
user7875786

Reputation:

Ajax Thymeleaf Springboot

I'm trying to use ajax with thymeleaf. I designed a simple html page with two input field. I would like to use addEventHandler for the value of first input text, then I want to send it to controller and make calculation, after that I need to write it in same html form in the second field which returns from controller.

For example:

first input text value -> controller (make calculation) -> (write value) in second input text.

My html page is

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <link rel='stylesheet prefetch' href='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css'>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>

<input type="text" name="Thing" value=""/>
<script th:inline="javascript">

    window.onload = function () {

        /* event listener */
        document.getElementsByName("Thing")[0].addEventListener('change', doThing);

        /* function */
        function doThing() {
            var url = '@{/testurl}';
            $("#fill").load(url);
            alert('Horray! Someone wrote "' + this.value + '"!');
        }

    }
</script>
<!-- Results block -->
<div id="fill">

    <p th:text="${responseMsg}"/></div>
</div>

</body>
</html>

My controller

 @RequestMapping(value = "/testurl", method = RequestMethod.GET)
public String test(Model model) {
    model.addAttribute("responseMsg","calcualted value")
    return "test";
}

However I cannot call controller from ajax. Could you help me?

Upvotes: 2

Views: 11538

Answers (1)

Dimitri Mestdagh
Dimitri Mestdagh

Reputation: 44665

There are a few issues with your code. First of all, it looks like you're using the same template for both the initial loading of the application, and returning the calculated result.

You should split these two into different calls if you're using AJAX, since one of the goals of AJAX is that you don't need to reload an entire page for one change.

If you need to return a simple value, you should use a separate request method like this:

@GetMapping("/calculation")
@ResponseBody
public int multiply(@RequestParam int input) {
    return input * 2; // The calculation
}

What's important to notice here is that I'm using @ResponseBody and that I'm sending the input to this method as a @RequestParam.


Since you will be returning the calculated value directly, you don't need the Model, nor the responseMsg. So you can remove that from your original request mapping.

You can also remove it from your <div id="fill">, since the goal of your code is to use AJAX to fill this element and not to use Thymeleaf. So you can just have an empty element:

<div id="fill">

</div>

Now, there are also a few issues with your Thymeleaf page. As far as I know, '@{/testurl}' is not the valid syntax for providing URLs. The proper syntax would be to use square brackets:

var url = [[@{/calculation}]];

You also have to make sure you change the url to point to the new request mapping. Additionally, this doesn't look as beautiful since it isn't valid JavaScript, the alternative way to write this is:

var url = /*[[ @{/calculation} ]]*/ null;

Now, your script has also a few issues. Since you're using $().load() you must make sure that you have jQuery loaded somewhere (this looks like jQuery syntax so I'm assuming you want to use jQuery).

You also have to send your input parameter somehow. To do that, you can use the event object that will be passed to the doThing() function, for example:

function doThing(evt) {
    var url = [[@{/calculation}]];
    $("#fill").load(url + '?input=' + evt.target.value);
    alert('Horray! Someone wrote "' + this.value + '"!');
}

As you can see, I'm also adding the ?input=, which will allow you to send the passed value to the AJAX call.


Finally, using $().load() isn't the best way to work with AJAX calls unless you try to load partial HTML templates asynchronously. If you just want to load a value, you could use the following code in stead:

$.get({
  url: /*[[ @{/calculation} ]]*/ null,
  data: { input: evt.target.value }
}).then(function(result) {
  $('#fill').text(result);
});

Be aware that $.get() can be cached by browsers (the same applies to $().load() though). So if the same input parameter can lead to different results, you want to use different HTTP methods (POST for example).

Upvotes: 14

Related Questions