16

I'm using Grails 2.3.7 and I have a controller action as follows:

def testData(){
    def result = [:]
    result['name'] = "Sales"
    result['type'] = "bar"
    result['data'] = [5, 20, 45, 10, 10, 20]
    [data: result as JSON]
}

In the testData.gsp I'd like to get the JSON object in javascript:

<script>
    $(document).ready(function(){
        var data = JSON.parse(${data});
    })
</script>

Then I got an exception:

Uncaught SyntaxError: Unexpected token {

on the line:

var data = JSON.parse({&quot;name&quot;:&quot;Sales&quot;,&quot;type&quot;:&quot;bar&quot;,&quot;data&quot;:[5,20,45,10,10,20]});

It looks like JSON is messed up. I think it used to work this way. Maybe it's new Grails? How can I fix this? Thanks.

Update: Problem solved. See the comments in the accepted answer.

Update2: When I check the app today, it failed again. I did what the docs required with the "raw" method but no luck. A workaround is to use the "Per Page Encoding". This one I tested thoroughly. It does work.

3
  • @dmahapatro I tried both. I'm getting new exception: Uncaught SyntaxError: Unexpected token & Commented Apr 23, 2014 at 19:29
  • You can set a variable using g:set and ${data} would give you the JSON String. Any reason you want it in script block. Commented Apr 23, 2014 at 20:04
  • @dmahapatro I need to send the json to javascript to render some data. Commented Apr 24, 2014 at 17:11

9 Answers 9

9

The problem is that the JSON is being encoded as HTML. Try the following instead:

Controller

def testData() {
    def result = [:]
    result['name'] = "Sales"
    result['type'] = "bar"
    result['data'] = [5, 20, 45, 10, 10, 20]
    [data: result as JSON]
}

GSP

<script>
    var data = ${raw(data)};
</script>

You don't need $(document).ready because the JS code

var data = ${raw(data)};

is generated on the server-side

Sign up to request clarification or add additional context in comments.

2 Comments

Hi Don, I tried this. Firebug shows that var data = {&quot;name&quot;:&quot;Sales&quot;,&quot;type&quot;:&quot;bar&quot;,&quot;data&quot;:[5,20,45,10,10,20]}; So is there something wrong on my server side code?
Thx @Don It seems this is related to Grails Security and all new grails application encodes values inside ${} as html. I'll just use the ${raw(data)} and keep the codec untouched. Good catch and thx for the help!
8

Working solution :

def action() {
  [data: data as JSON]
}

GSP page:

<g:applyCodec encodeAs="none">
    var data = ${data};
</g:applyCodec>

Comments

6

The encodeAsJSON() method works well for outputting JSON data into JavaScript:

Controller

def testData() {
   def data = [name: "Sales", values: [5, 20, 45]]
   [data: data]
   }

View (GSP)

<script>
var data1 = ${raw(data)};  //{name=Sales, values=[5, 20, 45]}
var data2 = ${raw(data as grails.converters.JSON)};  //{&quot;name&quot;:&quot;Sales...
var data3 = ${data.encodeAsJSON()};  //{"name":"Sales","values":[5,20,45]}  CORRECT!
</script>

Using raw() on a Groovy object does not produce JavaScript compatible output (see data1), and using it after the JSON converter results in unwanted &quot; encoding (see data2). Using encodeAsJSON() produces the correct output (see data3).

Documentation:
http://grails.org/doc/latest/guide/security.html#codecs

Update:
I've switched to using a taglib with:

out << "<script>const data = " + raw((data as JSON) as String) + ";</script>"

3 Comments

encodeAsJSON() is producing same result as data2, do you have any idea why ?
I'm not sure what's changed with encodeAsJSON(), but you might try going the taglib route (see update above). Works with Grails 3.0.
Tested with grails 3.2.8, the taglib version is working like a charm.
5

The following worked for me using Grails 2.4.3:

Controller:

def result = [:]
result['type'] = "bar"
result['data'] = [5, 20, 45]

model: [data: result as JSON]

GSP:

<script>
// this worked!
var data = ${raw(data as String)};
</script>

Produced desired result:

<script>
// this worked!
var data = {"type":"bar","data":[5,20,45]};
</script>

The accepted answer by Dónal DID NOT work for me:

Controller (same as my working example above)

GSP (did NOT work):

<script>
// did NOT work!!
var data = ${raw(data)};
</script>

Produced same bad result:

<script>
// did NOT work!!
var data = {&quot;type&quot;:&quot;bar&quot;,&quot;data&quot;:[5,20,45]};
</script>

1 Comment

I was having the same issue in Grails 3 and this solved it for me.
3

This worked for me in grails 3.1.9.

Controller:

def result = [:]
result['type'] = "bar"
result['data'] = [5,20,45]
result['key'] = token

[data:result as JSON]

GSP:

<script>

var data = '${raw(data as String)}';
var json = JSON.parse(data);
alert(json.type);

var authorization = json.key;

</script>

Comments

3

Not all grails versions support raw() method or g:applyCodec taglib.

The solution is to use <%= %> block to avoid escaping

 <%= users.collect({id:it.id,value:it.name}) as grails.converters.JSON%>

OR

<%= someJsString.encodeAsJavascript() %>

But best practice is to avoid using serverside generated JSON into GSP and refactor into getting the same JSON received via ajax request

1 Comment

Works in grails 3.3.2
2

In testData.gsp add

<%@page expressionCodec="none" %>

and in script

<script>
   $(document).ready(function(){
    var data = ${data};
})
</script>

Comments

0

This might also help, passing data as simple model and parsing it as JSON in gsp.

def testData() {
    def result = [:]
    ...
    [data: result]
}

On View

<%! import grails.converters.JSON %>
...
<script>
function parseModelToJS(jsonString)
{
 jsonString=jsonString.replace(/\"/g,'"');
 var jsonObject=$.parseJSON(jsonString);
 return jsonObject
}

$(document).ready(function(){
 var data=parseModelToJS('${data as JSON}');
 console.log(data);
});
</script>

http://www.oodlestechnologies.com/blogs/Parse-model-to-json-on-gsp-in-grails

Comments

0

You can do this,

import groovy.json.*
Map testMap = ['name': 'Test']
String jsonData = new JsonBuilder(testMap).toPrettyString()
render(view: view, model: ["data": jsonData], params: [:])

In your gsp:

 <script>
    var data = ${raw(data)};
</script>

Simple..

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.