How to declare javascript asset in the view to be rendered within the footer using Grails Asset Pipeline

146 views Asked by At

Since there is no deferred option for:

<asset:javascript src="custom_view_script.js"/>

What else can be used, outside of resource plugin, to place view specific script right before the closing body tag and without declaring it globally in layout?

I do know about:

<asset:deferredScripts/>

but that only handles on page script and not includes.

1

There are 1 answers

2
ncerezo On BEST ANSWER

The most simple way is using site mesh.

In your layout you need to put

<g:pageProperty name="page.script"/>

At the end of the body.

Then in the page you will do something like this:

<content tag="script">
<script type="application/javascript">
... your code here ...
</script>
</content>

Notice that the content tag (script) is any text that you specify, but to refer to that content from sitemesh you prepend "page." to it.

However, be careful because sitemesh properties are not cumulative, I mean, if you put two sections with content tag="script" only the last one will be used.

If you need that, as I usually do, you can accomplish it by using a custom TagLib that slightly modifies the SitemesTagLib:

class MyContentTagLib implements RequestConstants {

    static namespace = "mycontent"

    Closure addContent = { Map attrs, body ->
        if( body != null ) {
            def htmlPage = getPage()
            if( htmlPage instanceof GSPSitemeshPage && attrs.tag ) {
                def name = attrs.tag
                def sitemeshPage = (GSPSitemeshPage) htmlPage
                StreamCharBuffer currentContent = sitemeshPage.getContentBuffer( "page.$name" ) as StreamCharBuffer
                StreamCharBuffer newContent = wrapContentInBuffer( body )
                if( currentContent ) {
                    newContent.writeTo( currentContent.writer )
                    newContent = currentContent
                }
                sitemeshPage.setContentBuffer( name, newContent )
            }
        }
    }

    private AbstractHTMLPage getPage() {
        return (AbstractHTMLPage)getRequest().getAttribute(PAGE)
    }

    private StreamCharBuffer wrapContentInBuffer(Object content) {
        if (content instanceof Closure) {
            content = content()
        }
        if (!(content instanceof StreamCharBuffer)) {
            // the body closure might be a string constant, so wrap it in a StreamCharBuffer in that case
            FastStringWriter stringWriter=new FastStringWriter()
            stringWriter.print((Object)content)
            StreamCharBuffer newbuffer = stringWriter.buffer
            newbuffer.setPreferSubChunkWhenWritingToOtherBuffer(true)
            return newbuffer
        } else {
            return (StreamCharBuffer)content
        }
    }

}

Now you can keep the g:pageProperty in your layout but you would do this in your pages:

<mycontent:addContent tag="script">
<script type="application/javascript">
... your code here ...
</script>
</mycontent:addContent>

That should collect all the content you put in different views and templates and then show it up in your final html where your g:pageProperty tag is.