#{extends '../main.html'/}# #{set title:'Templates'/}# #{set tab:'management'/}# #{renderTagArgs 'docHome.html'/}#
Webpieces has an efficient templating system which allows to dynamically generate HTML formatted document. The template engine uses Groovy as an expression language. A tag system allows you to create reusable pieces of a webpage.
Templates are stored along-side their respective Controllers for rapid development and switching between view and Controller.
A template file is a text file, some parts of which have placeholders for dynamically generated content. The template’s dynamic elements are written using the Groovy language. Groovy’s syntax is very close to Java’s.
Dynamic elements are resolved during template execution. The rendered result is then sent as part of the HTTP response.
Let me give you a little more detail here though. The process for template to *.class file is this
I purposely divide the templating document into tokens, tags, and then GroovyGen as that is how webpieces is designed giving you just a little insight into the design can be very powerful
Lastly, we do something called Feature Testing giving you example after example on a full server which is located in these Feature testing directories. Throughout this page, we will link to specific relevant examples in github
The first phase of processing before groovy enters the picture is processing based on special tokens. The complete Token list is found in a file called TemplateToken.java. Don't be shy damnit, check that shit out. Damn I am funny(and a bit buzzed while writing this). Btw, for you guys who think documents should all be formal, get off your damn high horse! Make shit fun man and make people smile. We have way way too much formal documentation in this world that is boring as hell to read
The simplest way to make a dynamic element is to declare an expression. The syntax used here is *[${...}$]*. The result of evaluating the expression is inserted in place of the expression.
For example:
*[Client ${client.name}$
]*
If you can’t be sure of client being null, there is a Groovy shortcut:
*[Client ${client?.name}$
]*
Which will only display the client name if the client is not null. If client OR name is null, then an empty string will be displayed
Next, you can prefix variables or tag arguments with 'escOff#' like *[${escOff#body}$]* and that will not do any html escaping. This is useful when you want to pass the body of a custom tag in like so
*[#{somecustomtag}#Some body with html#{/somecustomtag}#]*
Now, the html inside the custom tag is assigned to 'body' so that in your somecustomtag.tag file, you can then have:
*[My link=${escOff#body}$]*
After all, it would be very annoying if the html went away and wasn't passed into your tag for you
Next, let's look at a Controller like so and the following template snippet:
*[public Action requiredNotExist() {
return Actions.renderThis();
}
Client ${client?.name}$
]*
In the case, the client variable is required but the controller did not set a client variable. This is very frustrating to debug in some web frameworks but we require client to be defined in this case and will error out pointing you to the exact line in the html. Let's say however you have multiple controller methods rendering this page and you want to make 'client' an optional variable. You then can add a $ at the end of client. You also will probably want a ? after that signifying to return null if client is null like so:
*[Client ${client$?.name}$
]*
Another example is a simple password field(notice, I no longer need a ?):
*[My password is ${password$}$
]*
Sometimes, you have a tag file with content something like this:
*[&{label, i18nKey}& is my label for i18n. Printout value= ${label}$ ]*
However, when you call the tag file, someone may not supply this label argument as part of the tag. In that case, you add the $ to the end of label like so such that clients can see label as an optional argument(if it is truly optional):
*[&{label$, i18nKey}& is my label for i18n. Printout value= ${label$}$ ]*
So, by default, you should not need $ much, but it is there so you can make tag arguments and also make variables optional so the controller does not need to set them. We suggest keeping most things required and having the controller pass in the variable set to null if you like but always having the controller pass it in
Webpieces comes with many built in Tags and many built in Groovy Generators(GroovyGen.java) which are more complex generators. The built-in ones will be discussed in the Tags and GroovyGen sections of this page. See those sections to learn to use this token further with the tags that can be used. Also, all the feature tests for different tags and html gen which use these tokens will be linked there
Rather than typing something like this in your html in many many locations:
*[Basic Hello World]*
It is preferable to use the RouteID so the url above is located only in 1 single spot in your entire application. This allows you to change the url in one place and it changes everywhere that you write the following html in:
*[Basic Hello World]*
Some routes may have parameters in the RouteModule like /edit/car/{id} and in this case, the *[@[...]@]* template token can accept parameters like so
*[Edit Car with id=${entity.id}$]*
This template token is not restricted to links and can be used anywhere in the html such as javascript, forms and other locations
Lastly, the *[@@[...]@@]* is reserved for now and eventually will reverse the route id to the absolute url instead of the relative url. More on routes can be found in the &{ 'Routes Reference', 'routesReference'}&
Feature test example code can be found here(or see the *[#{form}#]* tag which has tests for post as well):
In the case of html commenting like this
*[]*
The field tag will run and if expensive, it would slow your page down. Instead you can use the comment template tokens and any tags inside the comment will not run
*[*{ This field will not run and all html is ignored too = #{field something}# }*]*
The html fed into the test
and the test itself can be used to further understand
In some cases, you may want to create documentation using webpieces and you may even want to document how awesome webpieces is and copy/paste template code. I don't know about you, but I don't want to be typing > and < and I also don't want my webpieces tags to actually run. So, as an example, if I type this code up and pass in 'Dean' for the name variable:
*[
Hello ${name}$
*[Some example with ${name}$
]*]**[
]*
The following html will be sent back to the browser:
*[
Hello Dean
<h2>Some example with ${name}$</h2>
]*
So the end user instead of seeing an h2 title will see the html text snippet this way(and the webpieces one too) as:
*[Some example with ${name}$
]*
There is one slight annoyance no one has fixed yet. You can't print ]* in this escape sequence so instead the workaround is to split into two sets of escapes firstSetOfEscapes]*secondSetOfEscapes. We do this above in this templates.html file to display correctly the documentation
The html fed into the test and the test itself can be used to further understandOkay, so, this is a LAST resort. Let me repeat that for effect. THIS IS A LAST RESORT!! (ie. skip this section damnit!!!) Ok, so you are still here. Oh well, curiosity killed the cat just so you know. Please, please talk to your colleagues for other possible methods before using this one or hell, send me an email. Ok, so a template is parsed and groovy code is generated using certain logic depending on each template token. This token is special as it literally just inserts whatever groovy code you type inline into the template. Now, remember, groovy is serial(just like java) so you could add a script up top setting a variable and add a script down below reading that variable. This is too powerful, never should really be used backdoor! Why did I add this? Well, I trust you to do the right thing and in some cases, well, we need a backdoor to quickly fix some customer butt-ass issue. This is that back door. Ok, end of story and onto the next 'amaaaaaazing' template token, lol, I crack myself up.
hmmm, I haven't cared enough to directly test this yet, but manually did. Adding to my todo to add a feature test for this token
Ok, so I find it very annoying when I add the following code to an html file and the build doesn't break:
*[
]*
Why you ask? I am glad you asked because 1 year later I find out that some page is broken because that *.png file doesn't even exist. So, we added a checker that will break your build if it doesn't exist. Kick-ass you say....yeah, I thought so too so here it is
*[
]*
Now, if this png file doesn't exist anymore, your build breaks and you can actually fix your app instead of letting your customers experience crap. Man, We're good. Oh, wait, I forgot to mention, this also works inside the script tag(or other tags) as well like so
*[#{stylesheet href:'%[/assets/crud/css/blogpost.css]%', media:'screen'/}#]*
Oh wait, you haven't looked at the stylesheet tag yet. Man you are missing out, speed up
Creating an app in more than one language is a big pain no matter how you solve it. In html, to create a label or text that can vary the language, you use this template token with the default text as well as a key that will be looked up for the language like so
*[&{ 'Basic Hello World', 'helloworld'}&]*
Sometimes, you may pass a tag argument as the variable into the text like so:
*[&{ label, 'helloworld'}&]*
In this case, you could make label an optional argument so the client does not 'need' to supply the label but generally you will want the above instead so it fails fast and let's the developer know that he is missing a label. Here is the example just in case you need it to be optional though:
*[&{ label, 'helloworld'}&]*
A full example can be found in our feature test which tests our entire server works end to end with i18n at The Full TestI18N Example
Tags are looked up via a TagLookup.java class in webpieces and are called from the generated groovy code. Tags typically generate html and javascript code when invoked. Of course, every piece of webpieces is swappable so when you created your first project, we installed a module that overrides the default webpieces TagLookup.java class with TagLookupOverride which binds in MyHtmlTagLookup.java so as you can see, you can add as many custom tags as you like in webpieces. Of course, I really want the build to fail if you have files that use a tag that doesn't exist so any tag you create, you must also modify the build file plugin to tell it about the 'customTags' in build.gradle. Just search for 'customTags' and add to that array so that we can verify your templates are all good to release to production and your code is #beast.
Now, instead of making you create huge amounts of tags, we created quite a few built in tags so let's dig deeper into them and into the examples
Decorators provide a clean solution to share a page layout (or design) across several templates.
*[Use #{set} in the base template to set content into the layour and use #{get} to read that content in the super-template to fetch the content]*
Embedding a page in a decorator is the matter of a one liner along with setting the content with *[#{set}#]* tags. You will have many files like the following one with different content
*[#{extends 'simpledesign.html' /}
#{set title:'A decorated page' /}
#{set 'bigpiece'}
Large Content
This content is set into bigpiece variable to be fetched with #{get 'bigpiece'}#
#{/set}
This content is automatically stored in 'body' so use #{get body/}# in supertemplate to fetch this
]*
Then, you will generally have one layout template like so:
*[
#{get 'title'/}#
#{stylesheet href:'%[/assets/crud/css/bootstrap.css]%'/}#
#{get 'title' /}#
#{get 'body'/}#
#{get 'bigpiece'/}#
]*
A supertemplate can extend another supertemplate such that you can have a logged in template that then extends a logged out template for example where the logged in one has submenus. Some of the test files testing this feature are
Get and Set tags deserve their own section and detail. You may have a get tag that is optional so someone extending a template does not have to fill it in. To make the get optional and fill in with a default, you can do this
*[#{get key:'notexistkey', failfast:false}#COOL#{/get}#]*
In this case, if notexistkey is not set, then 'COOL' will be displayed. You may set html in a set method like so and it is escaped by default making life grand
*[#{set html:''/}# ]*
Or you may decide you do not want the html escaped
*[#{set html:'Title2
', escaped:false/}#]*
The set body defaults the other way since it is generally what you want so this html is 'not' escaped
*[#{set 'htmlbody'}#Some Header
#{/set}#]*
So, if you happen to want to type html and want us to escape it for you, set the escaped attribute to true
*[#{set 'htmlbody2', escaped:true}#Header3#{/set}#]*
These examples are simply copied from our get/set test here
In webpieces, you could simply use the html form element but the form tag adds a secure field that is checked on post. This ensures that the post comes from who we rendered it too. Other than that, the form tag does nothing additional for you. Test code can be found here:
One of our best tags. The stylesheet tag generates a url with a hash, so if a developer ever changes the stylesheet, it automatically changes the url the browser requests avoiding the previously cached version. No more modifying urls every time you change *.css files. The following is an example of using the stylesheet tag(along with the file check token to ensure the *.css file exists before deploying your production server):
*[#{stylesheet href:'%[/assets/crud/css/bootstrap.css]%'/}#]*
Please note that DevelopmentServer ignores this and forces the browser to never cache *.css files so you can edit to your hearts content in development mode. Test code can be found here:
Just like the stylesheet tag, this tag ensures a hash changes so you could always have your *.js file named jquery.js no matter what version it is.
*[#{script src:'%[/assets/crud/js/jquery/jquery.js]%'/}#]*
Test code can be found here:
This tag generates a ton of html/javascript code for AJAX list pages with edit and delete buttons. For example, you typically use it like so:
*[
FirstName
LastName
Email
Actions
#{list items:users, as:'entity'}#
${entity.firstName}$
${entity.lastName}$
${entity.email}$
Edit
#{bootstrapModal route:@[AJAX_EDIT_USER_FORM, id:'{id}']@, modalId:'addEditModal', linkId:'editLink_'+entity.id, id:entity.id/}#
Delete
#{bootstrapModal route:@[AJAX_CONFIRM_DELETE_USER, id:'{id}']@, modalId:'deleteModal', linkId:'deletePattern_'+entity.id, id:entity.id/}#
#{/list}#
#{else}#
There are no users, Add one now please.
#{/else}#
]*
The code it generates just for that AJAX_EDIT_USER_FORM route is jquery code like so:
*[]*
It actually does even more work then that handling redirects from the server as well. This is our primary tag for ajax List/Create/Edit/Delete flows in html and only works with twitter bootstrap. Test Code is found in these files
As a quick example, instead of writing this for 4 fields:
*[
${errors.forKey('user.name')}
]*
You can simply write this:
*[#{field 'entity.firstName', label:'First Name'}##{/field}#]*
You could even write less if you define a special *[#{textinputfield}# & #{passwordinputfield}# & #{textareafield}# & #{selectfield}#]* along with using the constructor of FieldTag.java if you desire and move all the *[ or
This is one of the most complex and advanced tags(and very very useful), the FieldTag can accept multiple *.tag files to create many versions so you can create a *[#{myfield}#]* tag in addition. You can also override the default field.tag file as well in your project. This tag works to save what the user typed in (in a scope called flash) as well as render tooltips and errors. This one tag can make all your tooltip/label/input/errorMsg/i18n common across your whole app so you can change the styling of all forms in one place. One example may be putting the error below the label/input for your whole app and then changing it so the error is on the same line as the label/input. See the userAddEdit.html file in your base.crud or base.crud.ajax packages in your project or look at our userAddEdit from our example project
#{renderTagArgs 'fieldTag.html'/}#Test code can be found here:
We prefer to use straight html when possible, but to flash what the user selects in a menu and then redisplay the same thing if his form has errors, we needed an option tag that basically render *[
*[#{field 'entity.levelOfEducation', label:'School Level'}#
#{/field}#]*
In that same file, there is also an example of a list of hibernate entities RoleDbo that a User has showing all roles a user could have as well as which roles the user is currently in (multiselect):
*[#{field 'selectedRoles', label:'Role'}#
#{/field}#]*
If you have a small snippet of a template you want to include, while you can create a whole tag just for that html with it's own name, another method is to use renderTagArgs like so:
*[#{renderTagArgs 'argsTemplate.html', tagarg:'cool', user:'override', user2:user/}#]*
Now, if you look at the controller, it also passes a 'user' variable. The renderTag args however passes a user variable such that the tag argument is used rather than the controller argument. If you want the controller args to pass through, then use the renderPageArgs tag. The test is shown here:
Like the renderTagArgs, this tag includes html but in this case uses the controller's variables that were passed in. The usage looks pretty much the same:
*[#{renderPageArgs 'argsTemplate.html', tagarg:'cool', user:'override', user2:user/}#]*
But, if you look at the test, the user variable comes from the controller not the tag argument. The test is shown here:
Sometimes you want to make an AJAX call to your webserver and re-render just a piece of your page. While *[bootstrapModal]* rocks for doing a popup, you may want to re-render just some table or section. In this case, you can get the correct remote call and then call it with code like the following:
*[]*
The jsAction combined with the reverse routing *[@[AJAX_EDIT_USER_FORM, id:'{id}']@]* creates a function getEditRoute which is then invoked 3 lines later. In this specific case, we are using jquery to 'load' and then telling a modal dialogue to show after it is done loading. See jquery and javascript if you don't understand the rest of the code as all we do is create a getEditRoute function for you to call and fetch the html. The server should just return 'partial' html from a template file that has just that piece of html that you wish to return.
To create your own custom tag, there is a few steps. The first step is to create your tag file like so:
*[TAG START
Inside, this custom tag, we can use any tag such as a link tag... Some Link Here
Can put the body out ${escOff#body}$
Or can print the args out ${someArgument}$
TagArgs from variable otherArgument=${otherArgument}$
TAG END]*
Let's say the full class path of this file is /org/webpieces/tags/mytag.tag. The next step is to add it to customTags property in your build.gradle file like so(hint: this property already is in the template with examples):
*[compileTemplateSetting {
//Since the groovy plugin has no way of knowing about your custom tags, list them here or the compile will
//fail (This catches mispellings and such so you don't release a broken app to production)
customTags = [ "mytag", "anothertag", "id", "myfield" ]
}]*
The next step is to modify the existing MyHtmlTagLookup.java and to have that class have a line that adds in the CustomTag() like so:
*[package org.webpieces.base.tags;
import javax.inject.Inject;
import org.webpieces.templating.api.ConverterLookup;
import org.webpieces.templating.api.HtmlTagLookup;
import org.webpieces.templating.api.RouterLookup;
import org.webpieces.templating.api.TemplateConfig;
import org.webpieces.templating.impl.tags.CustomTag;
public class MyHtmlTagLookup extends HtmlTagLookup {
@Inject
public MyHtmlTagLookup(TemplateConfig config, RouterLookup lookup, ConverterLookup converter) {
super(config, lookup, converter);
//add any custom tags you like here...
put(new CustomTag("/org/webpieces/tags/mytag.tag"));
}
}]*
For completeness, just to explain, there is a TagLookupOverride guice module like below and this is passed in on server startup in Server.java to override the default HtmlTagLookup class:
*[public class TagLookupOverride implements Module {
@Override
public void configure(Binder binder) {
binder.bind(HtmlTagLookup.class).to(MyHtmlTagLookup.class).asEagerSingleton();;
}
}]*
Like we have said in other parts of the documentation, you can swap pretty much any class in webpieces by binding a new subclass of the old version like this.
To create a more advanced tag, you can simply create a class extending HtmlTag.java and then modify MyHtmlTagLookup.java to add the new tag you created in there. In this case, there is no *.tag file and only an *.java file
While, these take on the same format as Tags in webpieces, these ones actually generate groovy code so they are run long before tags are run. GroovyGenerators(GroovyGen.java) run when you run your build, while tags run every time a page is rendered for a request. Yes, the groovy code generated by the GroovyGen is also run every time a page is rendered for a request as well but it's the generated code from GroovyGen that runs. From a user perspective however, we keep the syntax the same for ease of use of the platform
A simple generator so that if the variable positive is true as in this example, the html will be rendered:
*[#{if positive}#
This should exist
#{/if}#]*
Tack an else onto an *[#{if}# or an #{elseif}#]* to have a default if nothing else matches:
*[#{if negative}#
This should not exist4
#{/if}#
#{elseif negative2}#
This should not exist5
#{/elseif}#
#{else}#
Else3
#{/else}#]*
A simple elseif tag if the if doesn't match:
*[#{if negative}#
This should not exist4
#{/if}#
#{elseif negative2}#
This should not exist5
#{/elseif}#]*
iterates over a java List of things and assigns each thing or bean to a variable of your choosing. Here is an example:
*[#{list items:users, as:'entity'}#
${entity.firstName}$
${entity.lastName}$
${entity.email}$
&{'Edit', 'link.edit'}&
&{'Delete', 'link.delete'}&
#{/list}#
#{else}#
There are no users, Add one now please.
#{/else}#]*
Of note is the else statement. If there is 0 elements in the list and you have an else statement, you can tell the user there are no users instead of just having a blank table. The 'users' variable came from the controller and for each user in the list, it is assigned to the 'entity' variable which is then accessed like any other variable. Also of note in this is the special entity_index variable which you can use for styling even rows gray and odd rows white or just to name the id attribute differently.
Currently, users cannot create these but if there is enough demand, we could provide a plugin point to plugin into the gradle plugin that generates the groovy source. Until this time, just send me a pull request and I can add it directly into webpieces so everyone can use your Groovy Generator rather than being selfish and keeping it to yourself ;).
Remember the phases of compile, ScriptWriter.java first takes your template and generates a bunch of groovy code and in this stage, it uses GroovyGenerators to help. Then, the groovy is compiled to a java *.class file. Any tags that were part of the template are invoked only when the class file is invoked to generate the html(along with invoking any code generated from a GroovyGenerator as well). In this fashion, tags can only generate text/html and cannot generate groovy code like GroovyGenerators can.