You want to include a link to one of your Grails actions (say an AJAX target link) in one of your JavaScript files. What to do?

Well you could just inline your JavaScript in your GSP file, right? Then you can just access all the GSP tags you like and the problem just goes away, right?

<r:script>
console.log("Now hacking on ${assessment.id}");
$.ajax({
       type: 'GET',
       url: "${g.createLink(action: 'addThreat')}",
       data: { assessmentId : "${assessment.id}" },
       /* more JS magic here */
});
</r:script>

Well, yes, but then you have other problems (like wanting to take advantage of JavaScript compression and caching, and not to mention the general mental clutter of having all this magic happening in the same file).

I’m not sure how other people handle this situation, but I figure I’d document one pattern for tackling this problem in case you find yourself running up against it.

In my scenario, I have a workspace.gsp file for all the Grails-ey stuff and a workspace.js file which hosts all my jQuery code.

1. Use a JS Hash in your GSP file to save what matters

The general pattern I use is to create a namespaced JavaScript object in my GSP file which hosts all the links that I want to consume. This part I actually do inline, but there’s not a lot that could be compressed/cached, so I don’t stress about it. So my workspace.gsp file looks like this:

.. Normal GSP stuff here ..  

<!-- We inline the values (ids, action links, resource links) we want to use in our JS file -->
<r:script>

var GMARC = {
    assessmentId : '${assessment.id}',
    threatUrl: '${g.createLink(action: "getThreats")}',
    addThreatUrl: '${g.createLink(action: "addThreat")}',
    categoryIcon: '${g.resource(dir: 'images/icons', file: 'folder.png')}',
    assetIcon: '${g.resource(dir: 'images/icons', file: 'television.png')}'

  }

</r:script>
<!-- Next we pull in our JS file, and can reference GMARC.assessmentId, GMARC.assetIcon, etc -->
<g:javascript src="workspace.js"/>

2. Consume that JS hash in your JavaScript file to get what you need

With our GSP file in place, we can now move on to our workspace.js file where we can take advantage of all of those Grails values that we squirrelled away in our JavaScript hash. Here is an extract from my workspace.js file:

 $.ajax({
        type: 'GET',
        url: GMARC.addThreatUrl,
        data: { assessmentId : GMARC.assessmentId },
        dataType: 'json',
        success: function(json, textStatus) {
            /* Do JS Goodness here */
        },
        error: function(xhr, textStatus, errorThrown) {
          alert('An error occurred! ' + ( errorThrown ? errorThrown : xhr.status ));
        }
    });

In the JS above, I can take advantage of the GMARC.assessmentId (line 3) and GMARC.addThreatUrl (line 4) variables I declared in my GSP file, while keeping the JavaScript testable, cacheable and as clean as a whistle.

Well, that’s at least one pattern for cleanly using Grails variables in your JavaScript. Keen to know how other people approach this problem!