Passing data from controller to JavaScript in GSP - javascript

I want to pass data from controller to javascript by embedded data directly in view. (So there won't be additional requests.)
My first solution is to use as JSON in GSP like this:
<script>
var data = ${invoice as JSON};
</script>
I don't think it's good idea since I have to use (Grails 2.2)
grails.views.default.codec = "none"
or (Grails 2.3)
grails {
views {
gsp {
codecs {
expression = 'none'
}
}
}
}
Now, I found that I can create little taglib like this:
def json = { attrs, body ->
out << (attrs.model as JSON)
}
And I can use following code in GSP:
<script>
var data = <g:json model="${invoice}" />;
</script>
Now, the question. Is using taglib is best practice? If not, please give me the best solution.

Transforming the comment in answer. You can create your JSON String in the controller and pass it to the view. Grails 2.3.x have the raw codec that don't encode your content. More info about this codec here.
Example:
class MyController {
def index() {
String invoiceString = invoice as JSON
[json: invoiceString]
}
}
index.gsp
<script>
var data = ${raw(json)};
</script>

using grails 2.4.4.
Above answer did not worked for me.
so adding what worked for me.
Source:
http://aruizca.com/how-to-render-json-properly-without-escaping-quotes-inside-a-gsp-script-tag/
<g:applyCodec encodeAs="none">
var data = ${data};
</g:applyCodec>

Now, I'm upgrading to Grails 3.2.4. I found that Sérgio Michels' method is still work. Just make sure jsonString is a String object.
<script>
var data = ${raw(jsonString)};
</script>
If it is not a String object, you can use something like following code.
<script>
var data = ${raw(mapInstance.encodeAsJSON().toString)};
</script>

Related

Spring Boot and html not rendering javascript

I am trying to cache some results of a js script. (note this is working for other things like raw string data returned from a service, just not for this. Also note this is the first time I am trying to do it with a script and .js file.
Working:
in html:
<script src="https://www.notmydomain.com/script.js?param1=blah"></script>
not working:
in html:
<script src="/script.js?param1=blah"></script>
in #RestConroller method (from System.out.println's I know its returning the exact same thing as when I call the script directly):
#GetMapping("/script.js")
public String script(Model model, #RequestParam Map<String,String> allRequestParams) {
String parameters = inputParameterBuilder.buildParametersString(allRequestParams);
String js = pagesCacheService.getPage("script.js"+parameters, null, String.class);
if(null == js) {
js = resttemplate.getForObject("https://www.notmydomain.com/script.js" + parameters, String.class);
pagesCacheService.updatePage("script.js"+parameters, js, String.class);
}
return js;
}
Thanks,
Brian
Solved the issue: #GetMapping(value = "/script.js",produces = "text/javascript")

How to extract json objects into an external file?

I have this small code example:
<script type="text/javascript">
var texts = [{key:'key_1', value:'value_1'},
{key:'key_2', value:'value_2'},
{key:'key_3', value:'value_3'}];
</script>
I use a json array directly in my xhtml page by using the script tag. The json array "texts" is used by an another java script function in my xhtml page, but that is not important at the moment.
How can a extract this json array into an external file? Which library it must be used?
EDIT:
I use a java maven project and that should be include my external json file!
I tried this code but it doesn´t work:
<script type="text/javascript">
var placeholderTexts = himjQuery(document).getJSON('placeholder.json');
</script>
You can use each loop in jQuery
Just try this
$.each(texts, function(key, value) { }
please try the below.
var arraysel;
var json = { };
for(var i = 0, l = arraysel.length; i < l; i++) {
json[arraysel= [i].id] = arraysel= [i].value;
}
After reading many times your question, I think what you want is this:
Create a .js file, for example data.js, with your data... which is not a JSON-serialized object, but a real literal. Use pure JSON notation if you want.
var DATA = {"a":1, "b":2};
Import that "script" wherever you want to use your data.
<script type="text/javascript" src="./data.js></script>
Use this data from any place in your JS code, for instance:
console.log(DATA.a);
Please get JSON data from AJAX and evaluate response and store in variable
<script>
var placeholderTexts = new Object();
$(function(){
$.get('placeholder.json', function(data){
try{
placeholderTexts = jQuery.parseJSON(data);
console.log(placeholderTexts)
}catch(e){
alert(e.toString());
}
});
});
</script>

Safely Using JSON with html inside of the JSON in Django Templates

How do you safely render JSON data in a django webapp?
On the server in django I generate JSON data and then render that JSON data in a django template. The JSON occasionally contains snippets of html. Most of the time, that's fine, however if the </script> tag is inside the JSON data when it is rendered, it destroys the surrounding javascript.
For example...
On the server, in python I'll have this:
template_data = {
'my_json' : '[{"my_snippet": "<b>Happy HTML</b>"}]'
}
# pass the template data to the django template
return render_to_response('my_template.html', template_data, context_instance = c)
And then in the template:
<script type="text/javascript">
var the_json = {{my_json|safe}};
</script>
... some html ...
The resulting html works fine and looks like this:
<script type="text/javascript">
var the_json = [{"my_snippet": "<b>Happy HTML</b>"}];
</script>
... some html ...
However, you run into problems when, on the server, the JSON looks like this:
template_data = {
'my_json' : '[{"my_snippet": "Bad HTML</script>"}]'
}
return render_to_response('my_template.html', template_data, context_instance = c)
Now, when it's rendered, you'll get:
<script type="text/javascript">
var the_json = [{"my_snippet": "Bad HTML</script>"}];
</script>
... some html ...
The closing script tag within the JSON code is treated as closing the entire script block. All of your javascript will then break.
One possible solution is to check for </script> when passing the template data to the template, but I feel like there is a better way.
Safely insert the JSON as a string, and then call JSON.parse on it
Use escapejs instead of safe. It is designed for outputting to JavaScript.
var the_json = '{{my_json|escapejs}}';
To get a JavaScript object you then need to call JSON.parse on that string. This is always preferable than dumping a JSON-encoding into your script and evaluating it directly, for security reasons.
A useful filter to get python objects directly to the client that I use is this:
#register.filter
def to_js(value):
"""
To use a python variable in JS, we call json.dumps to serialize as JSON server-side and reconstruct using
JSON.parse. The serialized string must be escaped appropriately before dumping into the client-side code.
"""
# separators is passed to remove whitespace in output
return mark_safe('JSON.parse("%s")' % escapejs(json.dumps(value, separators=(',', ':'))))
And use it like:
var Settings = {{ js_settings|to_js }};

Call an action from JS file instead of the view (MVC 4)

I'm using the MVC 4.
In my view i can simply get an action's url by using the: #Url.Action
Now i wanted to make a javascript file with all the view's javascript instead of writing it all in the view, the problem is i can't use the razor's stuff anymore.
so my question is how can i get the action's url from a javascript separated file?
You'll need to define a JavaScript variable within your view that you can then use in your script. Obviously this must be declared first.
I use a helper on my layout pages that has all these variables and a section for any I'd want specific to a page. Note these would come before any other script references before the body tag.
#Scripts.Variables()
#RenderSection("ScriptVariables", false)
The Scripts.Variables is something like this
#helper Variables()
{
<script language="javascript" type="text/javascript">
var ActionGetallAdmin = '#Url.Action("GetAll", "Admin")';
var ActionAccountLogin = '#Url.Action("Login", "Account")';
</script>
}
One way I did this before was to create views that served JS files (and CSS files, actually), instead of HTML files. This leverages the fact that views aren't necessarily HTML files all the time in the MVC paradigm.
You could do this by creating a controller for it:
public class AssetController : Controller {
protected void SetMIME(string mimeType) {
// implementation largely removed
this.Response.Headers["Content-Type"] = mimeType;
this.Response.ContentType = mimeType;
}
// this will render a view as a Javascript file
public void ActionResult MyJavascript() {
this.SetMIME("text/javascript");
return View();
}
}
Once you've done that, you can create a view (using the way you normally do it in ASP.NET MVC), and just write it up as Javascript. Remember not to use a layout, as you obviously don't want that.
Everything that views in MVC has to offer is available to you, so feel free to use models, et al.
#model IList<Entity>
#{
Layout = null;
}
(function ($) {
// javascript!
#foreach(var entity in Model) {
$('##entity.Id').on('click', function () {
console.log('#entity.Name');
});
}
})(jQuery);
Then you can wire that up using old-fashioned Razor in your other views.
<script src="#Url.Action("MyJavascript","Asset")"></script>
Which will roll out something like
<script src="http://your.domain/asset/myjavascript"></script>
Works like a charm. The views are dynamically created, of course, so be wary if you're nit-picky about that. However, since they are MVC controller actions and views, you can set cache options on them just as with any other view.
Uhm... I think you can define a special route, like "actionsjs", that points to an action.
routes.MapRoute(name: "actionsJs",
url: "actionsjs",
defaults: new { controller = "Home", action = "GetActions" });
In the action you've to set the content to the right type:
Response.ContentType = "text/javascript";
Then you'll return a specific View that will contains javascript code with some Razor inside.
#{
Layout = "";
}
$(function() {
var a = #(1 + 2);
});
At this point you'll able to add this "script file" to your site:
<script type="text/javascript" scr="#Url.Action("GetActions", "Home")"></script>
Should work.
If you want the root path, use a variable on layout and use that in JavaScript file, say
// In layout view
<script>
var rootPath = #Url.Content("~/")
</script>
User rootPath anywhere in your application JavaScript files
If you want to get full path of a controller with action then
// View
<script>
var url = #Url.Content("ActionName", "ControllerName")
</script>
use url in your JavaScript file.

Embed raw data in HTML to parse in jQuery

I've been living in the desktop world for most of my career, so forgive me for asking such a basic question, but I'm not quite sure where to start looking.
I want to return some raw data along with my HTML, and parse and display the data using jQuery as soon as the HTML is ready. I know roughly what my js code should look like, but I'm not sure how I should embed the raw data in my HTML.
I could use $.getJSON(), but it'd be better if I could have the data right in my HTML.
I think either json or XML would work, but what's the proper way to escape/embed/parse these when they're embedded in HTML?
Thanks in advance.
You can put the JSON data in a hidden div, then decode and use from jQuery.
For example, we'll take:
{"foo":"apple","bar":"orange"}
Escape it and put in a div:
<div id="data">%7B%22foo%22%3A%22apple%22%2C%22bar%22%3A%22orange%22%7D</div>
Then from jQuery, we can use the data:
var data = jQuery.parseJSON(unescape($("#data").html()));
So calling alert(data.foo) will give us apple.
Here's a working example.
Where and when do you want this data?
If you want it in your view, just pass the data to the view
Action/Controller:
public ActionResult MyAction()
{
ViewData["MyData"] = "this is a sample data of type string";
return View();
}
And then, somewhere in your view:
<script>
var data = '<%= ViewData["MyData"] %>';
$(document).ready(){
alert(data);
}
</script>
<h1><%: ViewData["MyData"] %></h1>
Of course, if you're working with a List<string> or `string[]', you would need to format it to proper JavaScript for jQuery to understand it.
<script>
var dataArray = [
<% foreach(string s in (string[])ViewData["MyDataArray"]){ %>
<%= s %>,
<% } %>
];
</script>
It would be getter if you generated the proper JavaScript in the action instead of the view to avoid ugly markup in your view:
public ActionResult MyAction()
{
string[] myArray = new string[]{ "hello", "wolrd" };
ViewData["MyData"] = myArray;
ViewData["JavaScriptArray"] = "[" + myArray.Aggregate((current,next) => string.Format("'{0}','{1}',", current, next).TrimEnd(new char[] { ','})) + "]";
// or you can use your favorite JavaScript serialize
return View();
}
Now you can do the following in your view:
<script>
var dataArray = <%= ViewData["MyJavaScriptArray"] %>;
alert(dataArray[0]); // alerts 'hello'
</script>
Like you said it is probably best to get it via Ajax using $.post or $.get or $(element).load() etc...
But if you must save it in the page it is common to save in a hidden field. Asp.net saves things in hidden fields using binary serialization and Base64 but you can save it as a Json string and then use it in your JS.

Categories

Resources