Using JSP code in JavaScript - javascript

I want to use JSTL's fmt tag in JavaScript to localize my alert messages.
My JavaScript file is a standalone file and when I include fmt tag in js, the file browser gives JavaScript errors. Is it possible to treat .js file as .jsp files using web.xml configuration?
Can anyone please suggest how can I do that?

is it possible to treat .js file as .jsp file using web.xml configuration?
Yes:
<servlet>
<servlet-name>scriptjsp</servlet-name>
<jsp-file>/script.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>scriptjsp</servlet-name>
<url-pattern>/script.js</url-pattern>
</servlet-mapping>
But, there is no actual advantage in doing this, because JavaScript files do not have to have URLs ending in ‘.js’. What determines whether a file is a JavaScript file is what MIME media type it is served as. You can set this from JSP using:
<%# page contentType="text/javascript" %>
at the top. Then you can link directly to:
<script type="text/javascript" src="/script.jsp"></script>
(Aside: in current browsers, scripts linked to with the <script> tag will work even without having the Content-Type properly set, but that's probably not something to rely on.)
I want to use JSTL's fmt tag in javascript
This is probably not a good idea. The fmt tag deals with HTML-escaping for characters, but what you want is JavaScript string literal escaping, for example to backslash-escape quote characters. JSTL doesn't provide this capability. You'll get unexpectedly-escaped ‘&’ characters showing up in your JavaScript strings, and use of apostrophe or double quote in messages will break the whole script.
Also, serving commonly-included scripts from JSP risks poor performance and cacheing.
I'd suggest an independent language lookup system in JavaScript. For example, include a per-language external script:
<script type="text/javascript" src="/script/lang/en.js"></script>
(changing 'en' to match whichever language you want), and in that file define a lookup like:
var msg= {
messageName: 'Message in English',
...
};
Then look up msg.messageName for each localisable string in the script.

If your javascript is 'inline' with the rest of your JSP page, then simply use the technique suggested by Kees de Kooter.
If your javascript needs to be in an external file (For sharing across pages, for example) then simply put it in its own JSP file.
<%#page contentType="text/javascript" %>
<fmt:message key="some.message" var="someMessage"/>"
<fmt:message key="another.message" var="anotherMessage"/>"
var someMessage = "${someMessage}"
var anotherMessage = "${anotherMessage}"/>"
And include it like this...
<script src="yourScript.jsp" language="JavaScript" type="text/javascript"></script>
You can then refer to 'someMessage' and 'anotherMessage' from within the file that includes the JSP, or from any javascript file that is included after 'yourScript.jsp.
Note the use of the contentType attribute - 'text/javascript' prevents the JSP parser from complaining that the output isn't well formed XML - and that the tage refers to a JSP file.
A combination of this technique and that suggested by #Magner should bring you to a sensible solution.
EDIT: Changed the example to use 'text/javascript' insetad of 'text/plain' - thanks to #bobince for making me realise this error (Even though 'text/plain' works, it's more correct to use 'text/javascript'). Also, if the number of strings that need to be internationalised is small, and/or you can justify having your 'resources' in more than one place - one for the server side stuff and another for the client side stuff - #bobince's technique of using dynamic includes is a good one.

I would suggest you write a servlet that generates an array or javascript object that contains all the localized information you desire. You can use Java resource bundles which can be shared by both the client and server sides, then you don't have to intermix JSP code and Javascript code, and the servlet response will be cached by the browser.
Create a servlet, map it to a path, have it read the locale from a request parameter then generate the Javascript code.
Use a line like <script src="/mydict?lang=en"></script>
then load you script afterwards <script src="/myscript.js"></script>

You should strive to keep your javascript code in a separate file from the jsp-code. This is to get browser caching, easier maintenance, reuse across pages, and to allow compression.
I suggest that you create a global object for text in the jsp, to be used by your javascript files. Like this:
<script>
var text = text || {}; // play well with other jsps on the page
text.this_page_name = {
required_field_error: "<fmt:message key="required.field.error"/>",
system_error: "<fmt:message key="system.error"/>"
};
</script>
Later you use it in your javascript:
alert(text.this_page_name.required_field_error);

You could do the following. You store the translated message in a variable that can be resolved later on in the JSP.
<fmt:message key="your.alert" var="theAlert"/>
<script type="text/javascript">
alert("${theAlert}");
</script>

You can't use tags in JavaScript but there is a workaround: Put the tag into an hidden DIV (<div style="display: none;" id="msg"><fmt:...>
Now you can use JS to look up the DIV by its ID and get the innerHTML.
That said, fmt is just a wrapper for Java's i18n functions which you can use directly between <% %>.

If you are going for only alert messages
just use this tag in your javascript
Suppose you have following in your Javascript:
alert("Confirm Deletion");
This can be internationalized by adding bean:message tag in your javascript
alert('<bean:message key="msg.confirm"/>');
and add key value in property file
msg.delete=Confirm Deletion

Related

How to use jstl tags inside .js file? [duplicate]

I want to use JSTL's fmt tag in JavaScript to localize my alert messages.
My JavaScript file is a standalone file and when I include fmt tag in js, the file browser gives JavaScript errors. Is it possible to treat .js file as .jsp files using web.xml configuration?
Can anyone please suggest how can I do that?
is it possible to treat .js file as .jsp file using web.xml configuration?
Yes:
<servlet>
<servlet-name>scriptjsp</servlet-name>
<jsp-file>/script.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>scriptjsp</servlet-name>
<url-pattern>/script.js</url-pattern>
</servlet-mapping>
But, there is no actual advantage in doing this, because JavaScript files do not have to have URLs ending in ‘.js’. What determines whether a file is a JavaScript file is what MIME media type it is served as. You can set this from JSP using:
<%# page contentType="text/javascript" %>
at the top. Then you can link directly to:
<script type="text/javascript" src="/script.jsp"></script>
(Aside: in current browsers, scripts linked to with the <script> tag will work even without having the Content-Type properly set, but that's probably not something to rely on.)
I want to use JSTL's fmt tag in javascript
This is probably not a good idea. The fmt tag deals with HTML-escaping for characters, but what you want is JavaScript string literal escaping, for example to backslash-escape quote characters. JSTL doesn't provide this capability. You'll get unexpectedly-escaped ‘&’ characters showing up in your JavaScript strings, and use of apostrophe or double quote in messages will break the whole script.
Also, serving commonly-included scripts from JSP risks poor performance and cacheing.
I'd suggest an independent language lookup system in JavaScript. For example, include a per-language external script:
<script type="text/javascript" src="/script/lang/en.js"></script>
(changing 'en' to match whichever language you want), and in that file define a lookup like:
var msg= {
messageName: 'Message in English',
...
};
Then look up msg.messageName for each localisable string in the script.
If your javascript is 'inline' with the rest of your JSP page, then simply use the technique suggested by Kees de Kooter.
If your javascript needs to be in an external file (For sharing across pages, for example) then simply put it in its own JSP file.
<%#page contentType="text/javascript" %>
<fmt:message key="some.message" var="someMessage"/>"
<fmt:message key="another.message" var="anotherMessage"/>"
var someMessage = "${someMessage}"
var anotherMessage = "${anotherMessage}"/>"
And include it like this...
<script src="yourScript.jsp" language="JavaScript" type="text/javascript"></script>
You can then refer to 'someMessage' and 'anotherMessage' from within the file that includes the JSP, or from any javascript file that is included after 'yourScript.jsp.
Note the use of the contentType attribute - 'text/javascript' prevents the JSP parser from complaining that the output isn't well formed XML - and that the tage refers to a JSP file.
A combination of this technique and that suggested by #Magner should bring you to a sensible solution.
EDIT: Changed the example to use 'text/javascript' insetad of 'text/plain' - thanks to #bobince for making me realise this error (Even though 'text/plain' works, it's more correct to use 'text/javascript'). Also, if the number of strings that need to be internationalised is small, and/or you can justify having your 'resources' in more than one place - one for the server side stuff and another for the client side stuff - #bobince's technique of using dynamic includes is a good one.
I would suggest you write a servlet that generates an array or javascript object that contains all the localized information you desire. You can use Java resource bundles which can be shared by both the client and server sides, then you don't have to intermix JSP code and Javascript code, and the servlet response will be cached by the browser.
Create a servlet, map it to a path, have it read the locale from a request parameter then generate the Javascript code.
Use a line like <script src="/mydict?lang=en"></script>
then load you script afterwards <script src="/myscript.js"></script>
You should strive to keep your javascript code in a separate file from the jsp-code. This is to get browser caching, easier maintenance, reuse across pages, and to allow compression.
I suggest that you create a global object for text in the jsp, to be used by your javascript files. Like this:
<script>
var text = text || {}; // play well with other jsps on the page
text.this_page_name = {
required_field_error: "<fmt:message key="required.field.error"/>",
system_error: "<fmt:message key="system.error"/>"
};
</script>
Later you use it in your javascript:
alert(text.this_page_name.required_field_error);
You could do the following. You store the translated message in a variable that can be resolved later on in the JSP.
<fmt:message key="your.alert" var="theAlert"/>
<script type="text/javascript">
alert("${theAlert}");
</script>
You can't use tags in JavaScript but there is a workaround: Put the tag into an hidden DIV (<div style="display: none;" id="msg"><fmt:...>
Now you can use JS to look up the DIV by its ID and get the innerHTML.
That said, fmt is just a wrapper for Java's i18n functions which you can use directly between <% %>.
If you are going for only alert messages
just use this tag in your javascript
Suppose you have following in your Javascript:
alert("Confirm Deletion");
This can be internationalized by adding bean:message tag in your javascript
alert('<bean:message key="msg.confirm"/>');
and add key value in property file
msg.delete=Confirm Deletion

Why is my EL-statement only working in a script-tag where I do not import a js.file through a src-reference?

I have a javascript file, where I have collected login- and other user profile ajax calls that needs to be available on all of the pages in my web application.
For all of my ajax calls, I need the context path of the webapp to get the correct URL. A baseUrl-variable can be defined by var baseUrl = "${pageContext.request.contextPath}";.
I am experiencing a puzzling error though. If i try to initialize the baseUrl variable inside my login.js-file, it does not work. It is simply set to the string value "${pageContext.request.contextPath}" This .js-file contains all the scripts where I actually need the variable. However, if I define it inside a sourceless script-tag in the .jsp file itself, it works like a charm. (Code in the bottom)
I am guessing that this has something to do with when, and in which scope the expression is compiled and/or executed, and maybe also the difference between dynamic and static imports of code. I just can't wrap my head around exactly what is happening, and why my desired approach, to define the variable within the login.js-file, does not work.
Working import statement:
<script>var baseUrl = "${pageContext.request.contextPath}";</script>
<script src="<c:url value="/js/login.js"/>" type="text/javascript"></script>
EL expressions are only evaluated by the therefor capable servlets. Examples of such servlets are JSP's JspServlet and JSF's FacesServlet. The one is capable of evaluating ${...} in template text and the other is capable of evaluating both ${...} and #{...} in template text. The container's default servlet who's responsible for static resources like *.js files isn't.
Given that you're using JSP, just tell your webapp to use JspServlet to process any *.js requests. The container's builtin JspServlet has usually a default servlet name of jsp (at least, that's true for Tomcat and clones), so the below entry in your webapp's web.xml should do in order to get EL to be evaluated in *.js files.
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
This has one small caveat though. Some containers forcibly change the content type header to text/html regardless of the js file extension and then browsers got confused while downloading the JS file. One way to prevent that is to explicitly set the desired content type header in top of JS file the JSP way:
<%#page contentType="application/javascript" %>
A completely different alternative would be to print the context path as HTML5 data attribute of the <html> tag.
<!DOCTYPE html>
<html lang="en" data-baseuri="${pageContext.request.contextPath}/">
...
</html>
It's then just available anywhere in JS as below:
var baseuri = document.documentElement.dataset.baseuri;
Or if you're a jQuery fan:
var baseuri = $("html").data("baseuri");

Include javascript with resources via h:outputScript

I would like to include JScolor to my jsf application. It is possible via <script> tag, but I mean it is more system via <h:outputScript>.
However it is not working with resources. JSColor includes one js file and some picture files - it seems like the js file is included and the reousrces not.
Could anybody tell me why? And how to solve this?
Thank you.
The JS file is apparently referencing picture files via a relative path which do not represent a valid JSF resource URL.
The <h:outputScript> generates a JSF resource URL which goes through the JSF resource handler which worries about among others automatic localization and versioning. It would generate an URL prefixed with /javax.faces.resource and also append the currently used FacesServlet URL mapping such as *.xhtml or /faces/*.
Thus, if you mapped the faces servlet on *.xhtml and have a /resources/jscolor folder with the JS and image files and have referenced the JS file as follows,
<h:outputScript name="jscolor/jscolor.js" />
then it would generate
<script type="text/javascript" src="/context/javax.faces.resource/jscolor/jscolor.js.xhtml"></script>
However, the image files are not physically available in /javax.faces.resource/jscolor folder, instead they are physically available in /resources/jscolor folder. The /javax.faces.resource would only be automatically resolved when you apply the faces servlet mapping on the resource name. Thus, this specific case would only work if you manually edit the jscolor.js file to change image file names from e.g. arrow.gif to arrow.gif.xhtml.
If you don't utilize any automatic localization or versioning features of the JSF resource resolver, nor are using any special custom resource resolvers which requires real JSF resources rather than static HTML elements, such as this one, then you can also just go ahead with a plain vanilla HTML <script> element instead of a <h:outputScript>.
<script type="text/javascript" src="#{request.contextPath}/resources/jscolor/jscolor.js"></script>
I may misunderstand your question, but this snippet will help:
<script
type="text/javascript"
src="#{facesContext.externalContext.requestContextPath}/path/on/WebContent/foo.js"></script>
I regularly use this kind of java resource include, instead of the <h:outputScript>
add in web.xml
<servlet-mapping>
<servlet-name>Resource Servlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
Suppose your js file's path (file named jquery.js) into resources/js folder like that:
resources/js/jquery.js
Then you have to write:
<h:outputScript name="./js/jquery.js" target="body"/>
PS. Pay attention on attribute target (eg head, body)

Referencing ASPX controls from an External JS file

I have a question. I have a aspx control (for e.g textbox). I reference it using document.getElementById('<%=textbox.ClientID%>').value. When I have the code in the same aspx file it works. But as soon reference it from an external file (example MyJSFunctions.js), I cannnot. I get an error saying "the object does not exist or it is null"
I have included the name of the js file like
I did this because I like having all my js functions in a seperate file nad doing this also reduces the load overhead.
Why is this happening? Can I accomplish the same using jquery?
You will need to parametise your Javascript to accept the desired argument, then pass the inline ASP.NET script within the server-side page or control as the value of such. This will allow the engine to render the inline code appropriately.
It happens because the server renders your pages (not in the sense of a browser rendering HTML, but rather the ASP.NET engine making transformations to turn your .NETified web mark-up into standard web mark-up) prior to pushing them down to the client - this will only happen for "registered" types, and that doesn't (and shouldn't) include Javascript files (although you can technically register items to handle, unless you have a bespoke module to handle compilation of inline scripting among Javascript, then it would err anyway.)
jQuery essentially being something of a Javascript framework, you're in the same boat with that, so to speak.
As an example, consider the following...
Your script file:
function doSomethingJavascripty(withThisClientID) {
//do something with...
document.getElementById(withThisClientID).value;
}
Your ASPX page:
<script type="text/javascript" src="/path/to/script.js"><script>
<script type="text/javascript">
//call your function when appropriate...
doSomethingJavascripty('<%=textbox.ClientID%>');
</script>
One thing you could do is have the following Javascript code in your ASPX page:
var myTextbox = '<%=textbox.ClientID%>';
Then, in your external JS file (make sure this is after the above line), have:
document.getElementById(myTextbox).value
Another alternative is just hardcode in the ClientID into your code, but note you'll break it if you change the ID or parent container of that textbox control in the future.

Is it a good practice for a .js file to rely on variables declared in the including html

In short:
<script type="text/javascript">
var root = '${config.root}';
var userLanguage = '${config.language}';
var userTimezone = '${config.timezone}';
</script>
<script type="text/javascript" src="js/scripts.js"></script>
And then, in scripts.js, rely on these variables:
if (userLanguage == 'en') { .. }
The ${..} is simply a placeholder for a value in the script that generates the page. It can be php, jsp, asp, whatever. The point is - it is dynamic, and hence it can't be part of the .js file (which is static).
So, is it OK for the static javascript file to rely on these externally defined configuration variables? (they are mainly configuration, of course).
Or is it preferred to make the .js file be served dynamically as well (i.e. make it a .php / .jsp, with the proper Content-Type), and have these values defined in there.
You could follow the example used in jquery plugins. They define default values for the parameters in a specific format which could be overloaded by the user. So in my opinion it is OK to allow the user the possibility to define some variables in a documented format which would be used by the external script.
Assuming the specific values of your configuration variables are only known at runtime (ie the configuration can't be generated statically), it makes no sense to include the configuration in the actual script as that would make proper caching impossible.
It might be a good idea to dynamically generate a dedicated config.js on the server-side instead of embedding the configuration into the HTML if the rest of the page is static (or only re-generated on content change). If the page is dynamic anyway, I see nothing wrong with embedding the configuration.
If you subscribe to the philosophy of completely separating markup and scripting, you could encode the configration in the markup (eg via the lang attribute and cutom classes), but the purist viewpoint is not necessarily most pertinent.
In general, I would say it is best practice to make javascript files self-contained, and not depend on any external variables.
That said, there are some circumstances where depending on external variables is the right thing to do, and I would say this is one of them. Note:
The interface between the javascript and the external variables should be small and well-defined (as it appears to be in your example) - a small number of variables, each with a clear purpose, preferably set up from a common place in your page generation.
The information that changes is (presumably) small compared to the size of the javascript, so having a static javascript file enables caching to work much better.
It might be worth having a naming convention for the variables, so that anyone trying to maintain the javascript file can see clearly which are defined outside the javascript file itself.
Usually a better idea is to pass the config explicitly when initializing components defined in the external script, like this:
<script type="text/javascript" src="js/scripts.js"></script>
<script type="text/javascript">
MyApp.init(${config});
</script>

Categories