Adding a model attribute to the html template without encoding - spring-boot

I am using spring boot(ver. 1.1.1.RELEASE) and trying to add a string model attribute in a html template.
the Controller:
#RequestMapping({"/", ""})
public String template(Model model) {
model.addAttribute("coolStuff", coolStuff);
return "panel/index";
}
the HTML template:
<script type="text/javascript" th:inline="text">
/*<![CDATA[*/
[[${coolStuff}]]
/*]]>*/
</script>
thymeleaf's th:inline in mode "text" worked very well for that before, but now it is adding HTML encoding (escaping characters) to the provided string.
th:inline in mode "javascript" escapes double quotes so that is not working eihter.
Is there any way to put a string from a model attribute without encoding in the html template?

You can use th:utext to disable Thymeleaf's escaping but I'm not aware of a way to use that in combination with th:inline. I think you can still achieve what you want, but you'd have to change the value of coolStuff to contain the entirety of the <script> block.

Related

Using properties file constants as annotation values

I'm successfully loading messages for validation constraints from my properties file/s (i18n) but as I'm writing client side validation it's becoming clear that one source for both messages and constraint values could make the whole process less cumbersome.
In short: is there any way to load a value such as 20 for the size annotation from the properties file?
#Size(max=20)
private String password;
I have tried lines like:
#Size(max="${constraint.value}")
// or
#Size(max=Integer.valueOf("#{constraint.value}"))
But the value needs to be an Integer and a constant.
Edit1:
The client-side validation logic is done all over again in a form of a separate library, just the values like (5,10) for (min,max) are sticking out. (Using thymeleaf)
<script type="text/javascript" xmlns:th="http://www.thymeleaf.org" th:inline="javascript">
//...
// reading message from properties file
/*<![CDATA[*/
var errMessage = /*[[#{Size.user.userName}]]*/ 'default';
/*]]>*/
// adding a constraint to validationObj linked with one <input> element
validationObj.addSizeConstraint(ft.keyup,5,10,errMessage);
//...
</script>
Edit2:
Thanks to #Pavel Horal comment i made it work like this:
On the server side:
public static final int USERNAME_MAX_SIZE=20;
#Size(max=USERNAME_MAX_SIZE)
private String userName;
On the client side (or to the client side since it's preprocessed on the server side with thymeleaf) I'm getting this value like this:
<script type="text/javascript" xmlns:th="http://www.thymeleaf.org" th:inline="javascript">
//...
/*<![CDATA[*/
var value =/*[[${T(com.project.FormModel).USERNAME_MAX_SIZE}]]*/ 20;
/*]]>*/
//...
</script>
Which in my view is a better solution since I'm keeping all the values outside of javascript code. Thanks!
#Size annotation's max parameter only accepts an integer, so the below will not work anyway.
#Size(max="${constraint.value}")
On the other hand below also not working. "#{constraint.value}" will not resolve value from your property file. Also "${constraint.value}" will not work here too.
#Size(max=Integer.valueOf("#{constraint.value}"))
And for all annotations, annotation parameters should be constants by definition. So I actually can't imagine a potential solution for your problem.

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?
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).

Laravel blade #include into a Javascript variable?

In a Laravel 5 blade template I have a <script> section.
In this section I need to set a variable to a string that is coming from another blade template.
I tried something like :
<script>
var a = "#include 'sometext.blade.php' ";
</script>
but this obviously doesn't work.
Also, the included blade can contain both single and double quotes, so these need to be escaped somehow, or the Javascript will not be valid.
Any ideas?
Ended up needing similar functionality when working with DataTables, and the additional actions HTML needs to be injected after the fact via jQuery.
First I created a helper function with this (from Pass a PHP string to a JavaScript variable (and escape newlines)):
function includeAsJsString($template)
{
$string = view($template);
return str_replace("\n", '\n', str_replace('"', '\"', addcslashes(str_replace("\r", '', (string)$string), "\0..\37'\\")));
}
Then in your template you could do something like:
$('div.datatable-toolbar').html("{!! includeAsJsString('sometext') !!}");
to include the sometext.blade.php blade template with escaping of quotes and removal of newlines.

From Database to JS to Vue

Is it advisable passing some nonsensitive data to vue within an inline script?
HTML
<script>
var foo = <?php echo $foo ?>
</script>
Vue.js
new Vue({
data: {
foo: foo
}
});
This is probably a bit opinionated, but I'd avoid using a global variable like that in an application. Instead, I'd make use of HTML5 data- attributes and store useful bits of data the frontend needs in them.
You can do something like this:
<body data-my-thing='{"foo": "bar", "baz": true}'>
The above example uses JSON, what I'd normally do is use json_encode in a controller or view composer and just echo out the string like so (since we're using Balde here, the JSON is automatically escaped):
<body data-my-thing='{{ $myJson }}'>
If you were just using plain PHP then you should escape the JSON like this:
<body data-my-thing='<?=htmlspecialchars($myJson) ?>'>
Of course, you don't need to JSON, if it's more appropriate you can just store a plain string or number in there. It depends on the needs of your application.
To grab the value from your data attribute you'd just use the following JavaScript:
document.body.getAttribute('data-my-thing');
And if you've made use of JSON, don't forget to decode it!
JSON.parse(document.body.getAttribute('data-my-thing'));
I used to use data- attributes to bootstrap data, but I kept running into issues involving quotes.
Say that this:
<body data-my-thing='{{ $myJson }}'>
Evaluates to this:
<body data-my-thing='{"foo": "bar", "baz": true}'>
No big deal. What if your data looks like this?
<body data-my-thing='{"foo": "bar's", "baz": true}'>
Suddenly you have an issue. That's why I've used the script solution that the original poster mentioned above.

Why is my custom HTML Helper result getting html encoded?

I've got the following custom html helper in asp.net mvc 3
public static string RegisterJS(this HtmlHelper helper, ScriptLibrary scriptLib)
{
return "<script type=\"text/javascript\"></script>\r\n";
}
The problem is that the result is getting html encoded like so (I had to add spaces to get so to show the result properly:
<script type="text/javascript"></script>
This obviously isn't much help to me.. Nothing I've read says anything about this.. any thoughts on how I can get my real result back?
You're calling the helper in a Razor # block or an ASPX <%: %> block.
These constructs automatically escape their output.
You need to change the helper to return an HtmlString, which will not be escaped:
return new HtmlString("<script ...");

Resources