I am working on an MVC application and all the JavaScript for the pages is in their own JavaScript files, so there are no Script tags on the pages. Now, there is a Messages class that contains Errors, Information and Confirmation classes with Static strings. The error messages and information messages are being returned from the server, which is fine. But the confirmation messages (eg. Do you wish to Save (OK/Cancel), which is the confirm function in JavaScript) are hard coded in each JavaScript file. I now want the JavaScript to use the confirmation messages from the Messages.Confirmation class.
Currently, to solve this I do something like this in my page,
<%# Import Namespace="Business.Common" %>
.....
<script type="text/javascript">
confirmSaveQuestion= '<%= Messages.Confirmations.CONFIRM_SAVE %>';
</script>
and my .js file looks like this
var confirmSaveQuestion;
function ConfirmSave() {
var result = window.confirm(confirmSaveQuestion);
if (result)
return true;
else
return false;
}
and this works fine.
Is it possible to import the namespace Business.Common into the .js file, so that I don't have to set the value for confirmSaveQuestion in my page?
Your .js files are static, so there is no way for them to interact with server code. I'd recommend one of two things:
1) Use an ASHX handler to dynamically build javascript files - this will return your javascript dynamically, so that you can inject it with server stuff. Instead of referencing a .js file in your markup, you would reference your .ashx file.
2) Put the <%= %> tags into your master page - still shows up on the page, but at least you only have to deal with them once.
As I can't import namespace to my .js file, I went with a different solution. I removed the script tags from my page and instead added the following line of code. I guess it probably ends up doing a similar sort of thing, but it looks a bit cleaner.
<% Html.Telerik().ScriptRegistrar().OnDocumentReady("confirmSaveQuestion = '" + Messages.Confirmations.CONFIRM_SAVE + "'"); %>
Related
I use this for different languages on our site:
Locale locale2 = (Locale)session.getAttribute("org.apache.struts.action.LOCALE");
ResourceBundle bundle = ResourceBundle.getBundle("content.test.Language", locale2);
I can easy access the string values of the ResourceBundle in HTML to include it on the site via:
<%= bundle.getString("line1") %>
But in some cases I need to access the string values out of javascript.
I have not found a way to do this so far.
I only found a ugly workaround to get the string values.
On the HTML part I include:
<input type="hidden" name="hiddenLine2" id="hiddenLine2" value=<%= bundle.getString("line2") %>>
I do this for all strings I could possibly need.
To access one of them out of javascript I do this:
var line2 = document.getElementById("hiddenLine2").value;
This is working so far, but I donĀ“t like it.
I am sure there could be a better solution.
Some of the possible solutions.
Use an ajax method to get your resource by passing a key.
Use Hidden input fields and load values.
Use a dedicated jsp page to declare js variables or even a js function to get values according to key.
like this.
<script type="text/javascript">
var messageOne = '<%=bundle.getString("line1") %>';
var messageTwo = '<%=bundle.getString("line2") %>';
</script>
It is normally bad practice to use scriplets <% %> inside your jsp files.
You can use the fmt tag from the jstl core library to fetch information from your resource bundles.
<fmt:bundle basename="bundle">
<fmt:message var="variableName" key="bundleKey" />
</fmt:bundle>
<input type="hidden" name="hiddenLine2" id="hiddenLine2" value="${variableName}">
should work
infact, i think you can also directly embed it into the javascript with EL aswell
var line2 = ${variableName}; //instead of getting it from document.getElement(...)
Based on what I have tried, you can use jstl library to print the translated messages directly into JavaScript like:
alert("<fmt:message key='line1'/>");
And if you are using struts2 for handling the locales you can easily define you Bundles getting either the struts2 locale, saved by the i18nInterceptor present on the default stack, or the user request locale (the clients' browser one)
<!-- //Import the requierd libraries -->
<%#taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- //Take the Locale from struts if it's present and from the user request if not -->
<c:set var="locale" value="${not empty sessionScope.WW_TRANS_I18N_LOCALE
? sessionScope.WW_TRANS_I18N_LOCALE : pageContext.request.locale}"/>
<!-- //Get the bundle based on the Locale -->
<fmt:setLocale value="${locale}"/>
<fmt:setBundle basename="content.test.Language"/>
But if you want to be able to extract that JavaScript code into an external .js file on the future I recommend you to use some of the internalionalization libraries available for JavaScript, like Globalize (It's the only one I have used, but there are plenty on the net).
The downside of using an external JavaScript library for internationalization is that you will have to define the tranlation resources directly on .js files, it's impossible to access to your .properties on the server from a client-based language like JavaScript.
Here is a different solution.
Load bundle like OP did, with the method getBundle().
Using the third option on Arun's answer, create a separate JSP file to create a custom JavaScript object.
This is the content of said JSP:
<%#page import="com.tenea.intranet.conf.Conf" %>
<%#page import="java.util.ResourceBundle,
java.util.Enumeration" %>
<script type="text/javascript">
var _get = function(ID){
if (this.hasOwnProperty(ID)) return this[ID];
else {
console.warn("[Resources] Error al obtener clave <"+ ID +">");
return "[ERROR]";
}
};
var _search = function(text){
var elems = { }
Object.keys(this).map(e => {
if (typeof (this[e]) !== "function" && this[e].includes(text)) { elems[e] = this[e]; }
});
return elems;
};
var Resources = {
<%
ResourceBundle labels = ResourceBundle.getBundle("content.test.Language", locale2);
Enumeration<String> e = labels.getKeys();
while (e.hasMoreElements()) {
String param = e.nextElement();
out.print(param +":\""+ labels.getString(param) +"\"");
if (e.hasMoreElements()) out.println(",");
}
%>
};
Resources._get = _get;
Resources._search = _search;
</script>
What this JSP does is:
Creates object Resources
Using some snippets (sorry Martin :p), and iterating on the list of keys from the resourceBundle, for each key I print a line like "key: value" with out.println().
The resulting object is something like this:
Resources {
abrilAbrText: "Apr"
abrilText: "April"
...
}
To make some extra functionality, I also added 2 functions inside Resources.
_get() returns the text related to the key passed as parameter. If said key doesn't exist, return the text '[ERROR]'.
_search() is a function I added for development purposes. It searches and returns a custom object with every key whose corresponding text contains the text passed as parameter. NOTE: since it uses "e => {}", it won't work on IE or Safari, so it's best to comment it once the development phase has ended.
Once you have this JSP created, to use it you just have to import it to any JSP you want with this:
<%#include file="[relative_path]" %>
Hope it helps! :)
I'm sure this question has been asked multiple times, but the one example of the problem I'm having was asked about here.
Basically, if I have an ajax call to /Controller/Action, it works fine if I'm using my local development server of localhost/Controller/Action.
If I publish to UAT, the url needs more information. It's now server/application/Controller/action, which obviously breaks my ajax call.
<%: Url.Action("MyAction") %> solves this, but doesn't exist in the context of a seperate javascript file.
Currently, I have a javascript variable 'urlPrefix' in my app.js file, which I have to change between ""and "applicationName" everytime I debug locally or release to a different server.
What's the easiest way of solving this?
You can use:
#Url.Content("~")
to resolve the root path of the application, so there'll be no need to change it between deployments.
One way to implement this is to add the following to your <head> in _layouts:
<script type="text/javascript">
var rootPath = '#Url.Content("~")'; // includes trailing /
</script>
(use your namespace as required)
then you can generate your actions such as:
var url = rootPath + 'controller/action/' + id
I am working on a legacy application and I want to move some JS code onto a separate JS file.
I will have to refractor some of the code to do this. I can put #Url.Content statements into data attributes in the HTML.
But how would I replace this line of code?
var array = #Html.Raw(Json.Encode(ViewBag.JobList));
A separate JS file will not know what #Html.Raw means.
Server side code like that cannot run in a seperate javascript file. My solution for such problems is having a short javascript part in the head that runs on the onload event. There you can set variables that you can use in a seperate javascript file:
in the head:
array = #Html.Raw(Json.Encode(ViewBag.JobList));
in the seperate javascript file:
var array;
Then, in the seperate javascript file you can do with your array whatever is necessary.
The ViewBag.JobList data is only known at HTML page generation time. To include it in an external JavaScript file, you have to have another ASP.NET resource that recalculated ViewBag.JobList and then served as part of a dynamic JavaScript file. This is pretty inefficient.
Instead, do what you're doing with the URLs: pass the data through the DOM. If you're writing into normal DOM instead of a script block, you don't need the raw-output any more (*), normal HTML escaping is fine:
<script
id="do_stuff_script" src="do_stuff.js"
data-array="#Json.Encode(ViewBag.JobList)"
></script>
...
var array = $('#do_stuff_script').data('array');
// jQuery hack - equivalent to JSON.parse($('#do_stuff_script').attr('data-array'));
(Actually, the raw-output might have been a security bug, depending on what JSON encoder you're using and whether it chooses to escape </script to \u003C/script. Writing to HTML, with well-understood HTML-encoding requirements, is a good idea as it avoids problems like this too.)
I think you need to create action with JavaScriptResult
public ActionResult Test()
{
string script = "var textboxvalue=$('#name').val();";
return JavaScript(script);
}
But, before proceeding please go through following links
Beware of ASP.NET MVC JavaScriptResult
Working example for JavaScriptResult in asp.net mvc
I would also follow MelanciaUK's suggestion :
In your javascript file, put your code inside a function :
function MyViewRefactored( array ){
... your code ...
}
In your view, leave a minimal javascript bloc :
<script>
var array = #Html.Raw(Json.Encode(ViewBag.JobList));
MyViewRefactored( array );
</script>
I am using radcontrols in my porject and i want to restrict the radTextboxes should not allow the Special Characters so i am using script function inside my aspx page it is working properly, But i want to use this in entire project so i want to maintain a javascript file from that i want to use that function so help me on this how to pass textbox id and notification id to function. Here is my code
aspx
script file
function valueChangedHandler(sender, eArgs) {alert("Done");
var pattern = /^[a-zA-Z0-9\s]*$/;
var value = sender.get_value();
var matchArray = value.match(pattern);
if (matchArray == null) {
var notification = $find("<%=lblNotification.ClientID %>");
notification.set_text('Enter AlphaNumerics Only!');
notification.show();
sender.clear();
sender.focus();
exit();
}
}
notification code
<telerik:RadNotification runat="server" BorderColor="Black" BorderStyle="Solid" BackColor="ActiveBorder" BorderWidth="4" EnableRoundedCorners="true" EnableShadow="true" ID="lblNotification" Position="BottomRight" ShowCloseButton="true" Opacity="90" Title="Result" VisibleTitlebar="False">
</telerik:RadNotification>
above is working properly but i am not getting notification message so tell me how to pass notification id. with a small example.
You simply can't use server code blocks in an external JS file. They are parsed by the server only in aspx/ascx files. What you can do is to declare a function on the page that has the notification that will return the desired reference:
function getNotification(){
return $find("<%=lblNotification.ClientID %>");
}
Then the function in your JS file will call this function:
var notification = getNotification();
There are other ways of using ClientIDs in external files, e.g. creating an array in a global variable in the page, but if you do not want to rely on hardcoded IDs they will include code in the page. Well, you can also inject the script from the code-behind, but there isn't much of a difference.
Is it possible to write the below line in js file
var lst = #Html.Raw(Json.Encode(ViewBag.List));
You cannot use server side code in static js files. You could declare this global variable in the view and then use from separate javascript files.
You can made you js file dynamic, such as any other asp.net file by renaming it in
filename.aspx for example. Then your modded 'js' file will be something like:
<%# Page Title="" Language="C#" %>
<%
Response.ContentType = "application/x-javascript";
%>
function foo() {
var a = "<%= myVar %>";
}
you can include in your page with the standard way:
<script type="text/javascript" src="filename.aspx"></script>
Html Helpers can be used only in Views and not in the JavaScript files.
To make things work, you need to write your input variables to View and rest of the code in JavaScript files. So, your code should be like :
View:
<script>
var lst = #Html.Raw(Json.Encode(ViewBag.List));
</script>
and rest of the code to access "lst" will reside in javaScript file:
JS File:
$(document).ready(function(){
// access lst here, rest of the code goes here
});
Note: Do not forget to include JS file to View.
my fav solution is to give arguments as parameters:
function foo(parameter) {
var lst = parameter;
...
}
and in the View:
<input type='button' onclick="foo('#Html.Raw(Json.Encode(ViewBag.List))');" />
You may as well use an object to store every server side property and the pass it to your js as a global. Do it in the $(document).ready();. There's already a good question on SO, with more insights ont this. Will edit later with the link.
Regards,
EDIT: give a read to this SO question you'll find some more insights.