I want to access model items by index from JavaScript into a Play Framework template:
<script type="text/javascript" charset="utf-8">
window.onload = function()
{
var cl = ${colors.size()};
int i = 0;
for (i=0;i<cl;i++)
{
labels = labels + "${colors.name.get(i).escapeJavaScript().raw()}";
}
}
</script>
My problem is that this loop throws an exception:
IndexOutOfBoundsException : Index: 12, Size: 4
Nota 0: model = Color.
Nota 1: the size is 4.
Nota 2: if I test with a fixed number instead of variable i it is ok, but this is not what I need.
Cannot get why it does not work.
You try to use Groovy inside a Javascript loop which is wrong.
Remember your Groovy code (inside ${}) is evaluated by the Play templating on the server side and result of an HTML page returned to the client, and the Javascript is evaluated on client side (by the browser, not on your server).
maybe you want to do something like :
<script type="text/javascript" charset="utf-8">
window.onload = function()
{
labels = [#{list colors.name}"${_.escapeJavaScript().raw()}"#{if !_isLast},#{/if}#{/list}];
}
which is still dangerous if you don't understand what it does,
prefer using a simple AJAX request and the renderJSON method for dynamic loadings.
Related
I am trying to use d3-wordcloud(https://github.com/jasondavies/d3-cloud) in my GWT project. I included this in my .html file:
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" language="javascript" src="d3.layout.cloud.js"></script>
<script type="text/javascript" language="javascript" src="main.js"></script>
Where 'main.js' has a method which contains this code:
d3.layout.cloud().size([width, height])
.timeInterval(20)
.words(word_entries)
.fontSize(function(d) { return xScale(+d.value); })
.text(function(d) { return d.key; })
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.on("end", draw)
.start();
When I try to call the method from the .html file, the word cloud is generated fine. But when I do it from a java file (with $wnd), I get this error:
Uncaught TypeError: d3.layout.cloud is not a function' error
I think this might be because the d3.layout.cloud.js is written in node js and GWT doesn't know how to work with it.
Is that the reason? Is there a workaround?
Additional info: I use GWT 2.7. Good with java. Zero node js skills!
Feels like you need to simply use cloud()... instead of d3.layout.cloud()...
See line 10: https://github.com/jasondavies/d3-cloud/blob/master/examples/node.js
This question already has answers here:
Why split the <script> tag when writing it with document.write()?
(5 answers)
Closed 8 years ago.
How can I write a HTML-conform String to a new window using a JSP with inner Javascript?
Our Situation:
- Theres a .jsp-File used by a Tomcat-Server
- The .jsp contains a <script language="Javascript>-Tag
- this script needs to write a complete, HTML-5-valid-String to a new Window using window.open and 'window'.document.write(htmlString)
Our .jsp-File (schematic):
<%# include file = "..." %>
<...some page imports...>
<...some scripts...>
(e.g. <script type = "text/javascript" src="...."> </script>)
<%
String strMethod = "foo_Method_Bar";
String strOutput = "";
strOutput = someJavaBean-Call_that_brings_valid_html5_string_with_script-Nodes;
%>
...
<script language="Javascript">
var strHTML = "<%=strOutput%>";
var win = window.open('','','width=...,height=...');
win.document.write(strHTML);
top.close();
win.focus();
</script>
Our Problem (schematic):
- .jsp-File gets called.
- .jsp-File calls a JavaBean and sets a global String-Variable to the HTML-String (including <script>-Tags, DocType-Declarations, etc.)
- .jsp-File replaces all occurrences of the Variable with the obtained String
- javascript (<script>-Tag in the .jsp-File) gets Executed
- <script>-Tag of Javascript is already closed, before 'window'.document.write(strHTML) gets executed, because theres a </script>-Tag in the Javascript
e.g.
<script language="Javascript">
var strHTML = "<!DOCTYPE html> <html> ... <script> ... </script> ... </html>;
var win = window.open(...);
win.document.write(strHTML);
</script>
- I've searched for quite some time now and I don't have a clue how to solve this issue.
- Writing the HTML-Sourcecode into the Server-File-System and accessing it later on or something like that would be really, really dirty.
- Part of the Problem is that we (of course) have to use this type of javascript-call in the .jsp-File for historical reasons...;-)
- Is there maybe a way to assign the strHTML-Variable in the .jsp-File by Reference only (e.g. without replacing the <%=strOutput%>-Variable)?
Additional Info:
The HTML-String-Generation is used at various places of our programs, multiple times, so i hoped not to have to escape any special CharacterSequences for this particular Call to work.
Appreciate all your help and ideas on this...;-)
Solved:
See also Why split the tag when writing it with document.write()? on this issue.
You MUST escape the closing script in the string <\/script> unless the document.write lives in an external .script
Also remember to close the document, and no spaces in the parameters to window.open
like this
<script type="text/javascript">
var strHTML = '<!DOCTYPE html> <html> ... <script> ... <\/script> ... </html>';
var win = window.open("","winname","resizable,scrollbars");
win.document.write(strHTML);
win.document.close();
</script>
I have a jsp in Eclipse (Kepler SR2) and it's giving me a bunch of errors on this bit of code...
<script type="text/javascript">
$(document).ready(function () {
if (Boolean(${actionBean.saveSuccess})) {
$('#myTextField').focus();
}
});
</script>
It seems that the parser doesn't like me using EL in the middle there with ${actionBean.saveSuccess} to get at a java variable, though the code works correctly.
Is there some way to escape things so that the parser doesn't complain? Or possibly another way to accomplish the same result without angering the parser?
<script type="text/javascript">
$(document).ready(function () {
var a = '${actionBean.saveSuccess}';
if (a == true) {
$('#myTextField').focus();
}
});
</script>
if ${actionBean.saveSuccess} gives you boolean value than above code helps you
try this code it will surly help you
In an ideal world I would like to separate out Javascript to a completely different file and include it in the JSP page. But there are cases were I struggle to follow this rule simply because dynamically generated Javascript is so much easier to write !!
Couple of examples :
1) Locale specific error messages in alert boxes.
<%
Locale locale = ..//get current locale
%>
<script language="JavaScript">
function checkMessage() {
if(document.form.msg.value=='') {
alert(<%= *LocaleHelper.getMessage(locale,"please_provide_message")* %>); //get the locale specific message . mixing Javascript and JSP !!!
}
}
2) Initializing values .Sometimes you need to get values using JSP which will be used inside a javascript method
function computeExpiry () {
var creationDate= <%= creationDate =%>
var currentDate = document.form.date.value;
var jsCreationDate= converToDate(creationDate);
return currentDate>creationDate ;
}
3) Initializing config objects dynamically
var myConfig = {
modal:true,
resize:true,
<% if (lastPage) { %>
showPreviousButton :true,
showNextButton : false ,
showSubmitButton : true,
<%} else {%>
showPreviousButton :true,
showNextButton : true ,
showSubmitButton : false,
<%} %>
As you can imagine, without any kind of conventions , all our JSPs will be a unsightly mix of Javascript and JSP, hard to understand and maintain, with lots of non-reusable javascript code
I am not looking for a perfect solution. I know its easier to do this than try to maintain a pure Javascript and JSP separation. I am looking for suggestions to ease this process and hope lots of people have experience worth sharing.
Mixing JavaScript and JSP makes code harder to read, reuse, maintain and also degrades performance(such JS code cannot be externalized and compressed). Avoid that when possible.
One way is collecting all JSP related variables in one place and factoring out non-JSP codes into another pure/static JavaScript files. For example:
<script type='text/javascript' >
var app = { // global app "namespace" holds app-level variables
msg: "<%= *LocaleHelper.getMessage(locale,"please_provide_message")* %>";
creationDate: <%= creationDate =%>;
btnConfig: {
<% if (lastPage) { %>
showNextButton : false ,
showSubmitButton : true,
<%} else {%>
showNextButton : true ,
showSubmitButton : false,
<%} %>
}
};
</script>
// following JS has no JSP, you can externalize them into a separate JS file
// s.t. they can be compressed and cached.
function checkMessage() {
if(document.form.msg.value=='') {
alert(app.msg);
}
}
function computeExpiry () {
var creationDate= app.creationDate;
var currentDate = document.form.date.value;
var jsCreationDate= converToDate(creationDate);
return currentDate > creationDate;
}
var myConfig = _.extend({ // underscore library's extend
modal: true,
resize: true,
showPreviousButton: true,
}, app.btnConfig);
BTW, in practical application, I recommend module loader library like RequireJS instead of defining global variables primitively.
I try to avoid this but when I have to pass data from back-end to front-end I use a flat JavaScript Object which is created by a Hash in the backend. You can convert Hashes in any language to JSON strings. Place a <script> tag in your HTML page and dump that JSON string in it and assign it to a JavaScript variable.
For example:
<script>
var dataFromBackEnd = JSON.parse(<%= Hash.toJSON(); %>); // I'm just assuming JSP part
</script>
From this point JavaScript should take care about logic. If there is a condition that JS need to take action about it pass the boolean value of it to JS. Don't mix logic.
First you can do is avoing using scriptlets. Instead using it use JSP tags, as JSTL. It will allow you to format your code better.
My current project has me accessing a database quite frequently. To do so, I make calls to my Java Servlet through jQuery Get and Post calls. I was wondering if it was better practice to build any HTML using the data I gather from the database within the servlet before I ship it back to the jQuery or if I should do the HTML injecting with JavaScript alone? For example, let's say I have a database table with a user ID and a username. If I wanted to create a select box off this table, which would be the better way? Or is there even a better way? Would it be better to just try send the rawest form of the data retrieved from the database from the servlet to the JavaScript, allowing it to handle all of the HTML formatting?
Method 1 (Java)
Given the Following HTML/JavaScript
<html>
<head>
<script type="text/javascript" src="scripts/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$.get("servlet?cmd=getUsers", function(data) {
$("#select").html(data);
}, "html");
});
</script>
</head>
<body>
<div id="select"></div>
</body>
</html>
Using The Following Servlet
PrintWriter writer = response.getWriter();
response.setContentType("text/html");
writer.println("<select id='userSelect' name='user'>");
while(resultSet.next()) {
String userId = resultSet.getString("ixUser");
String userName = resultSet.getString("sName");
writer.println("<option value='" + userId + "'>" + userName + "</option>");
}
writer.println("</select>");
Method 2 (JavaScript)
Given the Following HTML/JavaScript
<html>
<head>
<script type="text/javascript" src="scripts/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$.get("servlet?cmd=getUsers", function(data) {
$("#select").html("<select id='userSelect' name='user'>");
$(data).find("user").each(function() {
var id = $(this).find("id").text();
var name = $(this).find("name").text();
$("#userSelect").append("<option value='" + id + "'>" + name + "</option>");
});
$("#select").append("</select>");
}, "xml");
});
</script>
</head>
<body>
<div id="select"></div>
</body>
</html>
Using the Following Servlet
PrintWriter writer = response.getWriter();
response.setContentType("text/xml");
writer.println("<xml>");
while(resultSet.next()) {
String userId = resultSet.getString("ixUser");
String userName = resultSet.getString("sName");
writer.println("<user>");
writer.println("<id>" + userid + "</id>");
writer.println("<name>" + userName + "</name>");
writer.println("</user>");
}
writer.println("</xml>");
I'd opt for sending raw (well, JSON) data to the client and have Javascript take care of the templating. Why?
Separation of concerns: Your server code shouldn't be aware of the presentation logic.
Less bandwidth: If you can save a few k/request (at least), why not?
It seems that the world is moving towards your second approach. There are several reasons for this:
Your users will perceive that your application is more responsive than it actually is because the page will be loaded in parts, so there is always progress being made (or at least a progress indicator if there is something that takes a long time to load).
You can re-use the data services for additional clients other than your website (think native mobile apps).
The data format is almost always more compressed than the html that is generated, so you send less data over the wire. I would actually recommend json over xml for this reason.
The javascript engines in most browsers are much more efficient than they were a few years ago. This allows you to offload some of the more complex page layout logic from your server, making your application more scalable.
It will be easier to test that the data returned is correct without having to wade through the formatting html to access it.
I'd suggest returning only the data in a lightweight manner such as JSON.
My reasons:
Bandwidth
Smaller data to be cached when performance concerns come into play
Flexibility. If you wanted to expose this data to another part of your application or a mobile device?
There are several other methods but in my mind this is a much more organized approach. Let the client deal with the markup processing.
I would suggest jQote2 as an awesome client side templating tool. (It's just awesome!)
These days the cool kids do MVC on the browser. -- Your method 2, but a more sophisticated client-side stack.
In other words, your server exports an api that provides data, not html.
Then, on the browser, your JS app has separate Model, View and Controller code. See the Backbone project for the Model and Controller layer, Mustache for the View/Template layer. An article. Another post.
method 1, as you are not comfortable enough with method 2.
a few words on method 2.
choose between string concatenation, or object building.
var html = '<select...
...
html .= '</select>';
$("#select").append(html);
or
var $sel = $('<select>').attr('id', 'userSelect').attr('name', 'user').
as you see, $('<tag>') syntax creates a new dom element.
Moreover, return a json object instead of xml if you can. They are more easy to work with in javascript.
So you can do
for (i in data) {
$('<option>').text(data[i].name).val(data[i].id).appendTo($sel);
}
$("#select").append($sel);
And then, there is method3: templating...