views:

2016

answers:

5

There are essentially 2 places to define JavaScript functions in Grails, directly in a element on the GSP, and within a separate javascript source file under /web-app/js (for example, application.js). We have defined a commonly reused javascript function within application.js, but we also need to be able to generate parts of the function dynamically using groovy code. Unfortunately, ${some groovy code} does not appear to be processed within separate javascript source files.

Is the only way to do this by defining the javascript function within a script tag on a GSP page, or is there a more general solution? Obviously we could define the javascript function in a script tag within a template GSP file which would be reused, but there is a lot of push to keep our javascript functions defined all together in one place (i.e. the external javascript source file). This has performance benefits as well (the javascript source files are usually just downloaded once by each client's browser, instead of reloading the same javascript functions within the source of every html page they visit). I have toyed around with the idea of breaking the function up into static and dynamic pieces, putting the static ones in the external source and putting the dynamic ones in the template GSP, then gluing them together, but this seems like an unnecessary hack.

Any ideas?

(edit: It may sound like the idea of dynamically generating parts of a JavaScript function, which is then downloaded once and used over and over again by the client, would be a bad idea. However, the piece which is "dynamic" only changes perhaps once a week or month, and then only very slightly. Mostly we just want this piece generated off the database, even if only once, instead of hard coded.)

+7  A: 

An easy solution to keep your JavaScript unobtrusive is to create a JavaScriptController and map its actions "/js/*" by adding this to your UrlMappings.groovy file:

"/js/$action"{
  controller = "javascript"
}

then just create an action for each dynamic JS file you want, include in in your layout <HEAD>, and presto, you've got a JS file that you can insert Grails snippets into! :)

Note: I've found that there's currently a bug in Grails that doesn't map file extensions to content-types properly, so you'll need to include <%@ page contentType="text/javascript; UTF-8" %> at the top of your view files.

gabriel
Very clever, thank you
Chris King
You're quite welcome! I ran into a similar problem last week, except I was dealing with CSS files :)
gabriel
A: 

There is another way - pass in the generated code into a function that expects closures. Those closures is generated by the program of course. The generated code is of course inlined/script-tagged in the gsp page.

it may or may not work depending on the nature of the code being generated. But i suspect it will work, and if it doesnt, minor tweaking to the coding style of your javascript will definitely make it work. Though, if these 'generated' code doesnt change much, this quite overkill imo.

Chii
+1  A: 

Or this... have a tag/service/dynamic method that lets tags write out their JS+CSS+whatever else, to a "cache" which is used to build the JS+CSS resources by a different controller.

Full concept here: [http://www.anyware.co.uk/2005/2009/01/19/an-idea-to-give-grails-tags-esp/][1]

Marc Palmer
+3  A: 

This is a great solution. I would like to offer a suggestion to use somthing other then a mapping of

"/js/$action" 
because this is no longer going to allow you to access you javascript files in /web-app/js/. All your javascript files would have to be moved to a the directory your controller would point to.

I would use something like

"/dynjs/$action"

This way you still can point to files in the /web-app/js/ files with out conflict and enjoy the benifits of gsp tags in javascript files

Please correct me if I'm wrong.

B Jammin
I would have added this as a comment but my reputation is currently below 50 so i can't comment on other peoples answers
B Jammin
Good point. Keep in mind however that you do not have to create a whole url mapping for "/js/$action", and can specify a single action directly, i.e. "/js/dyn.js"
Chris King
A: 

Regarding the JavaScriptController solution (sorry I'm unable to comment on the actual answer) is the idea therefore that I end up with my javascript code in files like grails-app/views/javaScript/xyz.gsp?

Fletch
Basically, yes - you can place javascript code in xyz.gsp, or you can simply output javascript directly using the render method in an xyz action in your JavascriptController.Keep in mind you can include the file with a link to javascript/xyz.js instead of just javascript/xyz or javascript/xyz.gsp because grails ignores file extensions for actions and views.
Chris King