How can I load static content into a gsp page? - grails

We have a grails project that is templated to produce two different sites. The sites have two different Frequently Asked Question pages but we would like to keep the template the same. We were thinking about including two different *.groovy files that have variables in them with the questions and then map those variables to a gsp page. Or maybe two different *.gsp files and the right one gets included at startup.
What is the best way to include the static content into the gsp page while reusing as much code as possible and how would I go about doing it?
Let me know if you need more information.

Grails have the concept of templates to reuse your view code. For example:
*grails-app/views/book/_bookTemplate.gsp*
<div class="book" id="${book?.id}">
<div>Title: ${book?.title}</div>
<div>Author: ${book?.author?.name}</div>
</div>
grails-app/views/book/someView.gsp
<g:render template="bookTemplate" model="[book: myBook]" />
grails-app/views/book/anotherView.gsp
<g:render template="bookTemplate" model="[book: myBook]" />
So you can use the render tag in any GSP that needs to use your template.

It is kind of late but I was looking for the answer myself. While there is no direct way to have insert static file in Grails, there are various ways you could accomplish so. From controller to custom tag. There is a code for custom tag:
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class HtmlTagLib {
// to be used in gsp like <html:render file="WEB-INF/some-static-file.txt"/>
// file param is relative to web-app folder
static namespace = 'html'
private static final Logger log = LoggerFactory.getLogger(HtmlTagLib .class)
def render = { attrs ->
String filePath = attrs.file
if (!filePath) {
log.error("'file' attribute must be provided")
return
}
String applicationPath = request.getSession().getServletContext().getRealPath( filePath )
def htmlContent = new File(applicationPath).text
out << htmlContent
}
}
Credits to Dónal on Rendering HTML files in Grails

Related

Grails: render file from assets folder into gsp

I use require.js in a Grails project. There are a couple of single JavaScript files containing the require.js modules defined with define.
There is also a *.gsp file which generates the require.js config and the entry point starting with require() as there is some dynamic configs to be generated. It looks somehow like this:
<%# page contentType="application/javascript;charset=UTF-8" %>
require(['a', 'b'], function(a, b){
...
var a = ${controllerPropertyA};
...
some functions
...
});
In my layout I integrate require.js like this:
<script data-main='http://example.com/exampleController/dynamicGenerateMethod?domain=xyz.com' src='http://example.com/assets/require.js'></script>
All the modules a , b, and so on are asynchronously loaded by require.js. Now I would like to bundle them into a single file - I could use the require.js optimize tool but I prefer to use the assets-pipeline. This works as far as that I get all modules bundled into a single optimized-modules.js which is available on http://example.com/assets/optimized-modules.js.
The question: I would like to have the optimized JavaScript code in the dynamically rendered GSP file. So how can I inject the optimized-modules.js file into the GSP I'm dynamically rendering? I already thought about a tag defined in the tag library so that my *.gsp would look like
<%# page contentType="application/javascript;charset=UTF-8" %>
<g:renderFile file="/assets/optimized-modules.js" />
require(['a', 'b'], function(a, b){
...
var a = ${controllerPropertyA};
...
some functions
...
});
and the tag definition somehow like that:
def g:renderFile = { attrs, body ->
def filePath = attrs.file
if (!filePath) {
throwTagError("'file' attribute must be provided")
}
//out << filePath
out << request.servletContext.getResource(filePath).file
//out << grailsResourceLocator.findResourceForURI(filePath).file.text
//out << grailsApplication.mainContext.getResource(filePath).file.text
//out << Holders.getServletContext().getResource(filePath).getContent()
//IOUtils.copy(request.servletContext.getResourceAsStream(filePath), out);
}
But I can't get the content of the minified optimized-modules.js which was done by the assets-pipeline plugin on startup. Any thoughts on this?
Ok, I finally found it out by myself:
Instead of using the grailsResourceLocator I had to use the assetResourceLocator which is the way to go if you try to access assets resources.
My tag definition now looks like:
def renderFile = { attrs, body ->
def filePath = attrs.file
if (!filePath) {
throwTagError("'file' attribute must be provided")
}
ServletContextResource bar = (ServletContextResource)assetResourceLocator.findAssetForURI(filePath)
String fileAsPlainString = bar.getFile().getText("UTF-8")
out << fileAsPlainString
}
That way I can inject a compile assets javascript file into my GSP - perfect!

Mapping URL in main menu to every page

I am using in my grails 2.3.4 project with spring security and spring securit ui.
I am having scaffolde my domain contact to the view. I have also a .gsp page which is not scarfolded.
My links from my main menue looks like that:
<li>Pricing</li>
<li>Contact</li>
Thats my URLMappings
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
"/private/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
"/"(view:"/index")
"/pricing"(view:"/pricing")
"/private/dashboard"(view:"/private/dashboard")
"/contact/create"(view:"/contact/create")
"500"(view:'/error')
}
}
My problem is when I am using this two links from my mainpage / then everythings works fine. However using them from 5432:localhost/TestApp/pricing I am getting the link 5432:localhost/TestApp/pricing/contact/create
which goes is not available. If I am using <li>Contact</li>, I am going to 5432:localhost/contact/create, which is also not available. How to go to contact/create from every page?
I appreciate your reply!
The simplest and safest approach would be
<li><g:link uri="/contact/create">Contact</g:link></li>
Other attributes on the g:link tag will pass through to the generated a tag, with the exception of id - you need to use elementId instead, as id is treated as a parameter to the link generation (controller/action/id)
<li><g:link uri="/contact/create" class="nav" elementId="contactlink">Contact</g:link></li>
would become
<li>Contact</li>
(where /TestApp is the application context path - if you deploy the app at a different context path then then link will change to match).

angular.dart how to create a custom component programmatically and add to page?

Is it possible to define an angular-dart component and then programmatically create an instance of that component and add it to your web page? I'd hoped there might be something like:
import 'package:web_sandbox/web_sandbox.dart';
import 'package:angular/angular.dart' as ng;
void main() {
document.body.appendHtml('<web-sandbox-component></web-sandbox-component>');
var node = document.body.query('web-sandbox-component');
ng.compile(node);
}
is there away of creating an angular web component programmatically and adding it to the page, maybe like the above pseudo-example, and if so how?
I don't think this is possible with Angular.
You can add an HTML tag <web-sandbox-component> into the DOM and tell Angular it should process this new HTML and then Angular would instantiate the Angular component for this tag (this is what the question you linked is about).
I don't see this as a limitation.
Is there something you would like to do that seems not possible this way?.
EDIT
Your code in main should look like this:
my document looks like
...
<body>
<div id="mydiv"></div>
...
</body>
and I append the <web-sandbox-component> to the div
main() {
print('main');
ng.Injector inj = ngaf.applicationFactory().addModule(new MyAppModule()).run();
var node = dom.querySelector('#mydiv');
node.append(new dom.Element.html('<web-sandbox-component></web-sandbox-component>', validator: new dom.NodeValidatorBuilder()..allowCustomElement("web-sandbox-component")));
ng.Compiler compiler = inj.get(ng.Compiler);
ng.DirectiveMap directiveMap = inj.get(ng.DirectiveMap);
compiler(node.childNodes, directiveMap)(inj, node.childNodes);
}

Multilingual in grails view

i'm working in Multilingual grails application (English and arbaic) , i want when the user chooses Arabic language the view's labels will be on the right side of the page and in English on the left side , how this can be achieved ?
thanks
You can use internationalization in grails through messages.properties file, you can define message signature in files and and they can be accessed through ?lang=es on the URL, you may need to have two files one for english and another for Arabic.
for example define in the messages.properties:
vendor.link.dashboardLink = Vendor Dashboard
and on the GSP page you can access it like:
<g:message code="vendor.link.dashboardLink" />
you can find more about internalization at grails doc have a look at http://grails.org/doc/2.2.1/guide/i18n.html
If the views have differences beyond simple string substitution, I would recommend using a different set of views based on locale:
Example controller code:
import org.springframework.web.servlet.support.RequestContextUtils as RCU
class ExampleController {
final static String englishLanguageCode = new Locale('en').getLanguage()
final static String arabicLanguageCode = new Locale('ar').getLanguage()
def differentViews() {
def currentLocale = RCU.getLocale(request)
switch(currentLocale.language) {
case englishLanguageCode:
render view: 'englishView'
break
case arabicLanguageCode:
render view: 'arabicView'
break
default:
// pick a default view or error page, etc.
}
}
}

Way to organize client-side templates into individual files?

I'm using Handlebars.js, and currently all my templates live inside script tags which live inside .html files housing dozens of other templates, also inside script tags.
<script type="text/template" id="template-1">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-2">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-3">
<div>{{variable}}</div>
</script>
...
Then I include this file on the server-side as a partial.
This has the following disadvantages:
A bunch of templates are crammed into HTML files.
Finding a given template is tedious.
I'm looking for a better way to organize my templates. I'd like each each template to live in its own file. For example:
/public/views/my_controller/my_action/some_template.html
/public/views/my_controller/my_action/some_other_template.html
/public/views/my_controller/my_other_action/another_template.html
/public/views/my_controller/my_other_action/yet_another_template.html
/public/views/shared/my_shared_template.html
Then at the top of my view, in the backend code, I can include these templates when the page loads, like this:
SomeTemplateLibrary.require(
"/public/views/my_controller/my_action/*",
"/public/views/shared/my_shared_template.html"
)
This would include all templates in /public/views/my_controller/my_action/ and also include /public/views/shared/my_shared_template.html.
My question: Are there any libraries out there that provide this or similar functionality? Or, does anyone have any alternative organizational suggestions?
RequireJS is really good library for AMD style dependency management. You can actually use the 'text' plugin of requireJS to load the template file in to your UI component. Once the template is attached to the DOM, you may use any MVVM, MVC library for bindings OR just use jQuery events for your logic.
I'm the author of BoilerplateJS. BoilerplateJS reference architecture uses requireJS for dependency management. It also provides a reference implementations to show how a self contained UI Components should be created. Self contained in the sense to handle its own view template, code behind, css, localization files, etc.
There is some more information available on the boilerplateJS homepage, under "UI components".
http://boilerplatejs.org/
I ended up using RequireJS, which pretty much let me do this. See http://aaronhardy.com/javascript/javascript-architecture-requirejs-dependency-management/.
I use a template loader that loads the template using ajax the first time it is needed, and caches it locally for future requests. I also use a debug variable to make sure the template is not cached when I am in development:
var template_loader = {
templates_cache : {},
load_template : function load_template (params, callback) {
var template;
if (this.templates_cache[params.url]){
callback(this.templates_cache[params.url]);
}
else{
if (debug){
params.url = params.url + '?t=' + new Date().getTime(), //add timestamp for dev (avoid caching)
console.log('avoid caching url in template loader...');
}
$.ajax({
url: params.url,
success: function(data) {
template = Handlebars.compile(data);
if (params.cache){
this.templates_cache[params.url] = template;
}
callback(template);
}
});
}
}
};
The template is loaded like this:
template_loader.load_template({url: '/templates/mytemplate.handlebars'}, function (template){
var template_data = {}; //get your data
$('#holder').html(template(template_data)); //render
})
there's this handy little jquery plugin I wrote for exactly this purpose.
https://github.com/cultofmetatron/handlebar-helper

Resources