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.
Related
This question already has answers here:
Access Java / Servlet / JSP / JSTL / EL variables in JavaScript
(5 answers)
Closed 5 years ago.
I want to read a jstl variable in a javascript function.
JS code submits a form.
$("#userSubmit").on('submit', function () {
document.getElementById("userForm").submit();
});
So in server code -
request.setAttribute("userId", 435);
and after the page is loaded -> in the javascript code -
$("#textBoxInp").keyup(function() {
// I want to access the userId here.
// in html code i can acccess it using JSTL syntax ${userId}
});
Just write the Expression Language directly in your JavaScript code:
$("#textBoxInp").keyup(function() {
var userId = '${userId}';
});
Note that this won't work if the JavaScript code is placed in a external file and is invoked in the JSP. In this case, you may refer to one of the four ways that BalusC explain here: Mixing JSF EL in a Javascript file (he explains five, but one of them is JSF specific).
One way is as suggested by Mendoza, but it will not work in case of having separate Javascript file.
in that case, another way is adding hidden field in JSP page, and reading same from Javascript.
JSP code:
<input type="hidden" id="xID" name="x" value="${myAttribute}">
JS code:
var myAtt = document.getElementById("xID").value;
If you want to access jstl variable in a javascript script function, you won't be able to access them directly. Here's a roundabout way(easy to implement) to do it.
In the HTML code have a paragraph with the required variable.
<p id = "var" disabled = "disabled">${variable}</p>
Access the variable using .innerHTML inside the JavaScript function.
function myFunction() {
var jstl_var = document.getElementById("var").innerHTML;
}
totalClients is jstl variable and to read in javascript block please see below
<script type="text/javascript">
$(document).ready(function() {
var tc = "<c:out value='${totalClients}'/>";
});
I am newbie to external javascript files (*.js). Basically I have my JSP ready but my manager wants me to add graphics in it.
So I found some *.js files. But I don't know how to communicate between them and my JSP page.
I want to pass data from jsp to external .js file.
Is there any mechanism to do that?
For e.g:-
Demo.jsp
out.print(request.getAttribute("Name"));
Now I want use/pass/set above value to main.js file how to do that?
<script type="text/javascript">
var myJavascriptVariable = <%= request.getParameter("Name")%>;
//or .getAttribute("Name")
</script>
This could do the trick, it will make a global Variable which could be accessed in main.js. When you have GET Parameters you could also use only JS:
var paramarr = window.location.search.substr(1).split("&");
var params = {};
for (var i = 0; i < paramarr.length; i++) {
var tmparr = paramarr[i].split("=");
params[tmparr[0]] = tmparr[1];
}
or a bit shorter:
var params = {};
// parse URL's GET parameters and iterate over them
window.location.search.substr(1).split("&"),forEach(function(el) {
var kv = el.split('"'); // split into [ key, value ] array
params[kv[0]] = kv[1];
});
Now you can access the parameter in JS via:
params['name']
Personally I would use AJAX (e.g. with the help of JQuery) to get Data for my JavaScript files, you can look at that at http://api.jquery.com/category/ajax/shorthand-methods/ (2018 edit: kust use native ajax calls or whatever JS framework is hyped this week ;-) )
If you are using .js file you can't write jsp sriptlet in it.
If you need to call value in .js file there is one simple way.
Assign values to input elements in .jsp page.(If you are not using values in .jsp page assign values to hidden input elements)
Then include.js file in your .jsp page
get values as javasript or jquery methods.
Ex:-
value= document.getElementById("element_id").value
OR If you are using jquery you can get as
value = $("#element_id").val();
You can declare a global js variable and assign the value.
<% String myValue = (String)request.getAttribute("Name"); %>
var global1 ='<%= myValue %>';
So here is what I want to do. I want to have a static HTML and javascript file in Google App Engine (by the way, I can write it in either Java or Python). So I want the user to visit my index.html file and get information from the datastore, but how would I do this?
I understand you must access the datastore from Java or Python, but once I get the data using these languages, how do I make it appear on myindex.html page (preferably without refreshing). I have tried to find this information everywhere, but all I can find is how to access the datastore using the two languages, not how to take that data and put it into my HTML page.
Cheers
The Python or Java app runs on the server, while any Javascript functionality you have is run on the client (in the web browser). AJAX is generally the best way to communicate between the two.
I assume that you had access data from datastore and you would like to show it on index.jsp .
Suppose your data is greeting with property "user" and "content" . then you can write like this in your jsp file.
if (greetings.isEmpty()) {
%>
<p>Guestbook '<%= guestbookName %>' has no messages.</p>
<%
} else {
%>
<p>Messages in Guestbook '<%= guestbookName %>'.</p>
<%
for (Entity greeting : greetings) {
if (greeting.getProperty("user") == null) {
%>
<p>An anonymous person wrote:</p>
<%
} else {
%>
<p><b><%= ((User) greeting.getProperty("user")).getNickname()
%></b> wrote:</p>
<%
}
%>
<blockquote><%= greeting.getProperty("content") %></blockquote>
<%
}
}
%>
You can use GqlQuery to get the data as a python object. Use GqlEncoder to convert from GQL to JSON.
self.response.write() the data to a url.
Then, with javascript, you can make an XMLHttpRequest to get the data from that url, and include the javascript into the html.
A stackoverflow question/answer on the XHR doing a similar task.
Traditionally we have always used xml in the response which is parsed by a Javascript method to execute post processes. I came up with a new, simpler implementation which uses a hidden input set by a requestAttribute and executed in an ajax callback.
JSP:
<%
String jsPostProcess = (String)request.getAttribute("jsPostProcess");
if (jsPostProcess!=null && jsPostProcess.trim().length()>0){
%>
<input type="hidden" id="jsPostProcess" name="jsPostProcess"
value="<%= jsPostProcess %> "/>
<% } %>
AJAX CALLBACK:
var callback = {
success: function(response) {
var div = $(divId);
if (div){
div.innerHTML = response.responseText;
}
var jsPostProcess = $('jsPostProcess');
if (jsPostProcess)
eval(jsPostProcess.value);
},
failure: function(response) {
alert('Something went wrong!');
}
}
SERVLET CODE:
request.setAttribute("jsPostProcess", jsPostProcess);
It works beautifully, and it is so much simpler for adding js post processes to virtually any call no matter how simple or complex the functionality is. No need for customized js methods for parsing.
Curious if anyone could identify any potential problems with it (such as security issues?) or make any suggestions for other alternatives. We currently use Prototype and YUI 2 on the front-end.
First, there's no need for that unpleasant scriptlet code:
<c:if test='${not empty jsPostProcess}'>
<input type='hidden' id='jsPostProcess' name='jsPostProcess' value='${jsPostProcess}'>
</c:if>
Next thing is that I hope that somewhere before this point the "jsPostProcess" value has been scrubbed so that it doesn't break the markup (like, in case it includes quotes).
Just calling eval() on the value like that seems a little dangerous, though perhaps you know pretty well what it's going to be.
Finally I would offer the suggestion that as an alternative to that, if the "post process" code isn't too big you could send it back in a response header. Then you wouldn't have to drop any meaningless markup into your page.
Oh, also finally: you might want to make the <input> be disabled. Or, alternatively, you don't even have to use an input: you can use this trick:
<script id='jsPostProcess' type='text/plain'>
${jsPostProcess}
</script>
Because the "type" attribute is "text/plain" the browsers won't try to execute that code, and you can get the "text" of the <script> element whenever you want.
I have a JSP where I'm using a javascript framework to build a chart using the Google Visualization API.
My servlet is returning a sales hashmap object with year as the key and integer (sales number) as the value.
My javascript uses the sales object to add data to the Google chart API which builds my chart.
code:
sales = '<%= session.getAttribute("sales") %>';
The sales object in my js gets the hashmap but it's a long string. Do I have to parse it in my javascript or is there a way it will automatically put the hashmap object properly into the javascript sales object?
you wont need to use an external json library (but you could!) - you can print out the json directly into a javascript variable like:
<%# taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<script>
(function(){
var sales = {
<c:forEach var="entry" items="${requestScope['sales'].entrySet}" varStatus="counter">
'${entry.key}' : ${entry.value} //outputs "2000" :1234 ,
<c:if test="${!counter.last}">, </c:test>
</c:foreach>
};
//js code that uses the sales object
doStuffWith(sales);
})()
</script>
Java and Javascript are completely different languages. Javascript doesn't know what do do with a Java HashMap object (actually in your example you'll get the output of HashMap.toString()). You'll have to serialize it into some form that Javascript will understand, eg. JSON.
Try using JSON which will allow you to describe your Java object in json ( java script object notation ) That way you can load the described object directly into javascript.
All this piece of code
sales = '<%= session.getAttribute("sales") %>';
does is print the value of session.getAttribute("sales") to the HTML output. Without any logic on your part as to how to format the output, Java will merely call .toString() on that Object - which the default implementation (unless you override it) usually results in an output that looks like classname#1234abc12.
So the short answer is that yes you will need to put in some logic on the Java side as far as how you would like your object / data structure to be output into the HTML document.