How I access a variable from JavaScript and Grails? - javascript

I have a Grails variable which is of type JASONList that is rendered in a template.
Is there a way to access this list from inside a JavaScript function?
Let's say I want onresize to fit all the objects on the screen. Without making a database call and refetching the entire list from Ajax...
Let's say the template does something like this:
<g:each var="report" in="${reportList?.myArrayList}">
<li style="display:inline; list-style:none;">
<img src=" ${report?.img}">
</li>
</g:each>
<script type="text/javascript">
function resize(list) {
if (list.size <givenSize) // Pseudocode
list.subList() // Pseudocode
}
window.onresize = resize("${reportList}")
</script>
The problem with this is that for some reason Grails gsp does not render "${reportList}" as a list. Instead it renders it as the string "${reportList}".
I am probably thinking of this problem completely wrong, but is there a way to resize these objects or get them through document.getElementById or something of that nature?
The $reportList is populated by POJO as JSON conversion...

Grails variables only exist on the server side. JavaScript runs in the browser (client side). Everything that's sent to the browser is a string, so while you can use Grails to generate a piece of JavaScript like window.onresize = resize("${reportList}"), the browser will only see the string that ${reportList} evaluates to.
That means that, if you use Grails to pass a variable to the resize() JavaScript function, the parameter (list) will only ever be a string - you won't be able to access server-side list methods like list.size or list.subList(), because the list variable is no longer a list; it's just a string.

I don't know, but maybe Grails doesn't want to evaluate expressions inside script tags. Dynamically generated scripts is not a very good practice.
But until you find the exact cause, you could try something like this:
<g:each var="report" in="${reportList?.myArrayList}">
<li style="display:inline; list-style:none;">
<img src=" ${report?.img}">
</li>
</g:each>
<%= """<script type=\"text/javascript\">
function resize(list){
if(list.size <givenSize) //posudo code
list.subList() // psudocode
}
window.onresize = resize(\"$reportList\")
</script>""" %>

I'm not sure why your ${reportList} is being rendered as ${reportList}, because when I do the following:
var t = "${taskList}";
I get the following in my HTML:
var t = "[com.wbr.highbar.Task : 1, com.wbr.highbar.Task : 4, com.wbr.highbar.Task : 2, com.wbr.highbar.Task : 5]";
That said, you're still going to have issues, because JavaScript will have no idea what to do with your reportList. If it is pure JSON, you would need to eval() it so that it gets turned into a JavaScript Object.

I figured out my problem. Basically if you are using POJO in Grails the Grails as JSON conversion is not very smart. All it does is a toString on the object instead of potentially looking at all the public accessors, etc.
It is kind of disappointing, but basically I need to create the JSON conversion in the toString method of my POJO.

Related

How do I pass a JSON object from JSP to Javascript?

I have a variable for myInitState that is initialized within a controller that is then passed to a jsp view.
<script>
myInitFunction({
myInitState: '${myInitState}',
componentName: 'myCompName',
divId: 'divId'
});
</script>
However by using '${myInitState}', in my Javascript I notice I get a string of "{...}" when debugging in browser. Is it possible to pass the object as json and have it be recognized as such or would I have re-parse the object within myInitFunction?
In order to take advantage of string interpolation, you need to use backticks
`${myInitState}`
You will then want to parse the string inside the function using JSON.parse(someString)
Updating answer here:
A couple of things I had left out of my question due to my misunderstanding:
- myInitState is a Map of <String,Object>
- The values of the map could be already escaped JSON blobs.
In this case the flow was from Server to client, so in order to convert the map into a JSON blob correctly I would need to do something like this in JSP:
<script>
var jsonBlob = {
<c:forEach items="${myInitState}" var="state" varStatus="loop">
"${state.key}": ${state.value} ${not loop.last ? ',' : ''}
</c:forEach>
};
</script>
However, a better approach, and what I went with, would be to just do conversion in the controller itself where myInitState is constructed.

parse javascript variable in .net getElementById?

I feel like I already know the answer to this is going to be "not possible" but just in case.
Let's say I have this javascript function used to read .net webform field's value:
function getById(theId) {
return document.getElementById(theId).value;
}
which I can call like this:
getById("<%=txtField1.ClientID%>");
Ok, that works fine.
But it is a given that .ClientID is always going to be in there, which means this function could be whittled down, but only if it is possible to represent the form field as a variable by itself. Something like this:
function getById(fieldName) {
return document.getElementById(<%= + fieldName + .ClientID%>).value;
}
to be called like this (much cleaner)...
getById("txtField1");
Is this possible?
Well yes and no/maybe.
Yes Part:
JS order of operations supports the ability to append strings before the get element call. For example if I had a textbox with id "searchTerm" then I could do this in js and be absolutely fine:
var check = document.getElementById('search' + 'Term').value;
NO Part: unless webforms differs significantly than what I remember way back when, that original function you have there is created to specifically get values when js is called inline and is about as optimized as you are going to get for that action. Once the page is loaded all of those server side variables will no longer be available for javascript and you would have to use the true client side elements IDs. Once workaround I suppose is to add onClick action to pass the client side ID such like so
<input type="text" onClick="WhatIsLove(this.id)" value="BabyDontHurtMe" id="Sing">

JavaScript - How to evaluate an EL with a JS variable inside? [duplicate]

I have a form in JSP. I have to populate it based on the request object (from the servlet). How do I use Java Script for accessing request object attributes or if you can suggest me any other better way to populate form dynamically?
You need to realize that Java/JSP is merely a HTML/CSS/JS code producer. So all you need to do is to just let JSP print the Java variable as if it is a JavaScript variable and that the generated HTML/JS code output is syntactically valid.
Provided that the Java variable is available in the EL scope by ${foo}, here are several examples how to print it:
<script>var foo = '${foo}';</script>
<script>someFunction('${foo}');</script>
<div onclick="someFunction('${foo}')">...</div>
Imagine that the Java variable has the value "bar", then JSP will ultimately generate this HTML which you can verify by rightclick, View Source in the webbrowser:
<script>var foo = 'bar';</script>
<script>someFunction('bar');</script>
<div onclick="someFunction('bar')">...</div>
Do note that those singlequotes are thus mandatory in order to represent a string typed variable in JS. If you have used var foo = ${foo}; instead, then it would print var foo = bar;, which may end up in "bar is undefined" errors in when you attempt to access it further down in JS code (you can see JS errors in JS console of browser's web developer toolset which you can open by pressing F12 in Chrome/FireFox23+/IE9+). Also note that if the variable represents a number or a boolean, which doesn't need to be quoted, then it will just work fine.
If the variable happens to originate from user-controlled input, then keep in mind to take into account XSS attack holes and JS escaping. Near the bottom of our EL wiki page you can find an example how to create a custom EL function which escapes a Java variable for safe usage in JS.
If the variable is a bit more complex, e.g. a Java bean, or a list thereof, or a map, then you can use one of the many available JSON libraries to convert the Java object to a JSON string. Here's an example assuming Gson.
String someObjectAsJson = new Gson().toJson(someObject);
Note that this way you don't need to print it as a quoted string anymore.
<script>var foo = ${someObjectAsJson};</script>
See also:
Our JSP wiki page - see the chapter "JavaScript".
How to escape JavaScript in JSP?
Call Servlet and invoke Java code from JavaScript along with parameters
How to use Servlets and Ajax?
If you're pre-populating the form fields based on parameters in the HTTP request, then why not simply do this on the server side in your JSP... rather than on the client side with JavaScript? In the JSP it would look vaguely like this:
<input type="text" name="myFormField1" value="<%= request.getParameter("value1"); %>"/>
On the client side, JavaScript doesn't really have the concept of a "request object". You pretty much have to parse the query string yourself manually to get at the CGI parameters. I suspect that isn't what you're actually wanting to do.
Passing JSON from JSP to Javascript.
I came here looking for this, #BalusC's answer helped to an extent but didn't solve the problem to the core. After digging deep into <script> tag, I came across this solution.
<script id="jsonData" type="application/json">${jsonFromJava}</script>
and in the JS:
var fetchedJson = JSON.parse(document.getElementById('jsonData').textContent);
In JSP file:
<head>
...
<%# page import="com.common.Constants" %>
...
</head>
<script type="text/javascript">
var constant = "<%=Constants.CONSTANT%>"
</script>
This constant variable will be then available to .js files that are declared after the above code.
Constants.java is a java file containing a static constant named CONSTANT.
The scenario that I had was, I needed one constant from a property file, so instead of constructing a property file for javascript, I did this.
In JSP page :
<c:set var="list_size" value="${list1.size() }"></c:set>
Access this value in Javascipt page using :
var list_size = parseInt($('#list_size').val());
I added javascript page in my project externally.

passing variable values from c# to javascript

First of all, sorry for bringing a question that has been answered so many times, but I have tried most of the procedures mentioned and still can't get it working.
I have an ASP.NET app (server-side), and I would like to visualize some results by using WebGL (JavaScript, client-side). I am able to create the canvas in aspx file and to draw a 3D object (a cube) by writing ALL the necessary JS code in a jscript file (As long as I know what I want to draw in advance, and writing all that in Jscript). However, my intention is to write a different object depending on my server-side code. When I click a visualize button, a postback is triggered. In the server some code is executed, and some coordinates are returned in an array, defined global in the aspx.cs file. I would need to pass that array of node coordinates from the server to the JS file in order to draw actually the object I want.
Here is basically what I have tried:
The easiest way I have found to pass a variable is to declare a property public in aspx.cs (c# code) and then in JS writing:
var clientVariable = '<%=ServerVariable%>';
I have tried this not with an array, but just with a string variable and if writing:
alert(clientVariable);
I see "<%=ServerVariable%>" in the window, NOT the actual value. I don´t know if I need any additional library or what. If I can't even get this easy example working, I don't know how I would even do it with a double array. I´m using MCVS08, ASP.NET 3.5 with HTML5.
Apart from that, I have tried to convert the array not with JSON, but with:
Page.ClientScript.RegisterArrayDeclaration();
I've used ClientScript.RegisterStartupScript(GetType(), "alert", "test2('" + A + "');", true);
I've tried to use a hidden block to store the session value, etc.
So basically, summing Up, I would like to have:
server-side: after executing a function of the code behind in the server, when rendering the page again I will have a global variable in aspx.cs which is a double[,] coordinates, containing the coordinates of nodes that will define the 3D object.
aspx: in html (not asp.net) I have a canvas tag in which I intend to have the visualization. The script that will render the image client-side is stored in a JScript file. In this file, inside a function I have a variable var vertices = []; which I need to feed with the values I got from the server in coordinates array. I don't know how to achieve this the best way. Would you recommend to use AJAX?
Any suggestion/comment would be very appreciated. As the dummy example with a simple string is not working (forgetting about canvas, webGL and all that stuff), may I need anything else or am I misunderstanding how to do it properly?
When I need to pass variables into JavaScript I usually I prefer var clientVariable = '<%=ServerVariable%>'; solution. This method is sufficient for small number of scalar variables. If you need to pass a complex object or a array, consider to use JavaScriptSerizlizer.
The behavior you are having it might happen for number of reasons. One of them might occur, if you have included a scriptlet into .js file, and not into .aspx file.
Here is how I would do this:
webgl-draw-file.js:
window.WebGlDraw = function(points /* point array */)
{
// Draw points here
}
Page1.aspx.cs:
public string GetSerializedServerVariable()
{
new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ServerVariable);
}
Page1.aspx:
<html>
<header>
<script src="webgl-draw-file.js"/>
<script type=text/javascript>
window.WebGlDraw(<%=this.GetSerializedServerVariable()%>);
</script>
</header>
<body>
...
</body>
</html>
To understand a better what values are passed to the JS function, take a look at a page source using your browser. You should see a JSON representation of your array instead of <%=Page.GetSerializedServerVariable()%> scriptlet.
It should look something like this:
<html>
<header>
<script src="webgl-draw-file.js"/>
<script type=text/javascript>
window.WebGlDraw([{x:1, y:2}, {x:1, y:2}, {x:1, y:2}, {x:1, y:2}]);
</script>
</header>
<body>
...
</body>
</html>
can u serialize the data like this:
<% var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); %>
var doublearr = <%= serializer.Serialize(ServerVariable) %>;

Embedding C# code using <%= code %> within javascript <script> tags

I'm using ASP.NET MVC and would like to get Model information for use within my javascript. I've strongly typed the view, and thus am able to use <%= Model.Name %> within my HTML to get Model data.
But once I'm in the <script> tags, I get no intellisense (in Visual Studio) when using <%, and the information doesn't seem to be rendering properly. Is there something I'm missing to be able to use the angle bracket scheme within Javascript?
Thanks.
CLARIFICATION: I should have posted the code I'm trying to use the first time around. To elaborate a bit more, I'm trying to use JQuery's $.getJSON to get data from the Model (via the Controller), and populate a JSON object. The javascript I'm using is below:
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("<%=Url.Action("PopulateJournalOptions", "Evaluation", Model.ID) %>", populateJSON);
});
</script>
PopulateJournalOptions is my Controller Action, Evaluation is my Controller Name, and Model.ID is what I'm trying to pass to it. Incidentally, I should be able to achieve the same thing using:
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("/Evaluation/PopulateJournalOptions/<%= Model.ID %>", populateJSON);
});
</script>
But even here, I'm not sure those angle brackets are being used correctly. It definitely looks a bit off. Thanks for the help.
UDPATE: Went ahead and tried the second method above and it does indeed work. I'm still having trouble using the first method that uses Url.Action(), which is a shame because I think it's the better method. But the <% tags are definitely rendering data now. I guess it just threw me when there was no intellisense and they didn't highlight like normal. Thanks for the quick responses. Any ideas on the right format for the first option above?
Generally speaking, <%= %> blocks should only be used within quotes in Javascript. Because you're inside quoted text, Intellisense may not work.
It ought to work - your C# should execute server side before the JavaScript does clientside. Intellisense may just be confused by the context.
I use this technique with PHP and JavaScript sometimes.
You need to be careful when writing strings into script tags, because as it is javascript the expectation is that the string has special characters encoded properly. Additionally, if that string contains something like "</script>" you run the risk of browsers that aren't running javascript ending the script block early.
An easy way to encode the strings is with a JSON serializer, perhaps JavaScriptSerializer().
<script>
var targetUrl = <%= (new JavaScriptSerializer()).Serialize("http://url/") %>;
</script>
I think this is safer. You'd want to put this code in a helper function, I just instantiate JavaScriptSerializer() in-place there so its the simplest example possible.
One side effect of this is that the <%= %> expression is not within quotes, which sounds like it would help your original autocomplete support issures. Note that Serialize() will not only properly escape the string for javascript, it will also escape-encode the '<' and '>' characters so that "</script>" scenario can't happen.
Correct me if I'm wrong, but I've never seen Url.Action used like this:
<%= Url.Action("PopulateJournalOptions", "Evaluation", Model.ID) %>
shouldn't it be like this?
<%= Url.Action("PopulateJournalOptions", "Evaluation", new { ID = Model.ID } ) %>
Note new { ID = Model.ID }
Url.Action uses reflection on an object's properties to figure out what the route values are. Since an int object has no fields/properties, it will not detect anything.
You might try single quotes:
$.getJSON('<%=Url.Action("PopulateJournalOptions", "Evaluation", Model.ID) %>', populateJSON);

Categories