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.
Related
I am send Sending a list from server to thymeleaf through model attribute
friendsOnlineModel.setFriendsOnline(defaultFriendRequestService.getFriendsOnline(user) == null ? Collections.EMPTY_LIST : defaultFriendRequestService.getFriendsOnline(user));
chatModel.setChats(defaultChatService.getUnreadChats() == null ? Collections.EMPTY_LIST : defaultChatService.getUnreadChats());
model.addAttribute("friends_online", friendsOnlineModel);
model.addAttribute("chats", chatModel);
I dont want to display them straight in an "li" tag, but rather pass it to a js function which displays them. Is it possible?
There are a couple ways you can do this. You could use JavaScript inlining, and add the data directly into your page. Similar to the example:
<script th:inline="javascript">
var fiendsOnline = [[${friends_online}]];
var chats = [[${chats}]];
</script>
Then you can deal with them in javascript however you want.
Or, instead of putting these attributes on the model, you can add them to a different controller method annotated with #ResponseBody. Then you call that method using ajax, and Spring will return your object as JSON.
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).
I am trying to pass the contents of a bean to javascript so that I can parse it and create a JSON object... (Yes I am still on ATG 9.1). However I am having trouble getting from serverside to client side.... I am new with this stuff and would appreciate any explanation as documentation on this is scarce and not helpful.
<dsp:tomap var="cartMap" bean="MyShoppingCartModifier.order" recursive="true"/>
<script>
var myCartMap = "${cartMap}";
//Logic (easy)
</script>
Doing this generates an "Uncaught SyntaxError: Unexpected token ILLEGAL" on my browser (Chrome)
Any wisdom will greatly help me in my quest in learning this stuff.
The problem is your usage of the tomap tag. You can't just pass in an entire tomap'd object because the tomap tag isn't going to create a nice, parsable json object.
You should either:
1) Format the json yourself right within your tags. Choose only the values that you want from the order.
<script>
var myCart = {
total : '<dsp:valueof bean="MyShoppingCartModifier.order.priceInfo.total">'
...
}
// Then use myCart for something here
</script>
or 2) There's a little known JSP to JSON library found here, http://json-taglib.sourceforge.net, that is very useful. To use that, you'd create a separate page, something like orderJSON.jspf, that is used to generate a pure json object from your order. Then in the page that you require this js, you can do:
<script>
var myCart = <%# include file="/path/to/orderJSON.jspf" %>
// Then use myCart for something here.
</script>
I would like getting the value of two textarea from WYMeditor:
The first one:
<script type="text/javascript">
jQuery(function() {
$(" .wymeditor").wymeditor({
logoHtml: '',
lang: 'fr',
skin: 'default',
});
});
</script>
And the second one:
<script type="text/javascript">
jQuery(function() {
$(" .wymeditor_ref").wymeditor({
logoHtml: '',
lang: 'fr',
skin: 'silver',
});
});
</script>
HTML:
<textarea id="definition" class="wymeditor" name="definition"/></textarea>
<textarea id="references_definitions" class="wymeditor_ref" name="definition"/></textarea>
I'm using this: WYMeditor.INSTANCES[0].html();
But, the problem is I don't know how to do if there are two textarea. How getting the second value?
Thanks a lot!!
Get specific WYMeditor instance HTML with known ordering
If you simply want to iterate through the results of all the WYMeditor instances on a particular page, your array index method is just fine. If you know the order in which the WYMeditor instances are created, you'll do something like:
var wymResults,
wymRefResults;
wymResults = WYMeditor.INSTANCES[0].xhtml();
wymRefResults = WYMeditor.INSTANCES[1].xhtml();
Get HTML from all WYMeditor instances
If you have an unknown number of instances of WYMeditor, this is how you might get the results of all of them:
var results = [],
i;
for (i = 0; i < WYMeditor.INSTANCES.length; i++) {
// Do something with the xhtml results
results.push(WYMeditorINSTANCES[i].xhtml());
}
Get specific HTML results with unknown instantiation order
If it matters which WYMeditor instance you'd like to retrieve though, which is often the case, you'll want to store references to the specific instances when you create them. eg.
var wym,
wymRef,
wymResults,
wymRefResults;
// Instantiate my WYMeditor instances
wym = $(".wymeditor").wymeditor();
wymRef = $(".wymeditor_ref").wymeditor();
// Let's grab the results. This will probably live in some kind of `submit()` handler.
wymResults = wym.xhtml();
wymRefResults = wymRef.xhtml();
Use xhtml(), not html()
Another note specific to your example, but you should be using the xhtml() call instead of the html() call to ensure consistent, cross-browser markup.
The html() call doesn't run the resulting HTML through the parser or do any browser-specific cleanup, which means that if you were to load some html in lets say IE9 that was created in Chrome, just calling html() without making any changes will mean the resulting HTML will be slightly different. Different browsers need HTML that is slightly different to provide a consistent editing experience, and WYMeditor abstracts this away for you, assuming you use xhtml() to get the results.
I am using AntiXssLibrary 4.0 but it not escaping \x3c. What is my mistake?
I have configure the AntiXss to be a default HttpEncoder based on here http://haacked.com/archive/2010/04/06/using-antixss-as-the-default-encoder-for-asp-net.aspx and set the encoderType of httpRuntime in web.config.
I also create AntiXSSEncoder derived from HttpEncoder but instead of deprecated
output.Write(AntiXss.HtmlEncode(value));
I use this to override the HtmlEncode method:
output.Write(Encoder.HtmlEncode(value));
Currently if I browse this:
http://localhost:28453/?k=sss\x3cscript\x3ealert%28\x27haaha\x27%29;\x3c/script\x3e
The alert "haaha" shows the AntiXss library is not working. I just want to make like this show http://channel9.msdn.com/Events/MIX/MIX10/FT05 see on the minute 13.
To be confirm I also set this in an action:
public ActionResult Index(string k)
{
ViewBag.k = k;
ViewBag.j = Microsoft.Security.Application.Encoder.HtmlEncode(k);
return View();
}
Then in the view I put this:
<script type="text/javascript">
$(document).ready(function () {
var a = '#ViewBag.k';
var b = '#ViewBag.j';
$('.resultName:first').html(b);
});
</script>
From the browser, the value a and b is the same which is shows the AntiXss does not working well!
<script type="text/javascript">
$(document).ready(function () {
var a = 'sss\x3cscript\x3ealert(\x27haaha\x27);\x3c/script\x3e';
var b = 'sss\x3cscript\x3ealert(\x27haaha\x27);\x3c/script\x3e';
$('.resultName:first').html(b);
});
</script>
Update: It only happened when I use the AntiXssEncoder as encoder type. When I comment this and rebuild. the single quote ' escaped by the MVC. Seems the AntiXss disabled! am I missing something? I want this working because I want like \x3c also escaped like the video.
<!--<httpRuntime encoderType="AntiXSSEncoder, MVCWeb"/>-->
You're right in that, since 4.0 .NET has encoded apostrophes in HTMLEncode, and AntiXSS does not, because, strictly speaking it's not necessary for HTML strings, only for attribute strings.
Now once you swap AntiXSS in as the encoder that assumption no longer applies, and people do, willy-nilly, apply Html encoding everywhere.
So when I push the next version of AntiXSS it will encode apostrophes all the time.