Applying layout to template at Runtime in Grails Application
There are use cases where we render the template from our action and update some div in the page using ajax.
The downside of this approach is when the user hits the url directly in browser address bar and the UI get totally messed up.
- Create annotation in src/groovy folder
[java]
package com.sony.common.annotationimport java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target@Target([ElementType.METHOD])
@Retention(RetentionPolicy.RUNTIME)
public @interface Ajaxed {String layout() default "main"
}
[/java] - Apply annotation to the controller method
[java]
@Ajaxed()
def searchPlayers(PlayerSearchCO playerSearchCO) {
List<Player> players = searchService.search(playerSearchCO)
render(template: ‘players’, model: [players: players, teamParticipant: playerSearchCO.teamParticipant])
}
[/java] - Add Filter to apply layout
[java]
applyLayoutForAjax(controller: ‘*’, action: ‘*’) {
before = {
if (controllerName && actionName && !request.xhr) {
def controllerClass = grailsApplication.controllerClasses.find { it.logicalPropertyName == controllerName }
def action = ApplicationContextHolder.resolveBean(controllerClass.fullName).class.declaredMethods.find { field -> field.name == actionName }
def annotation = action ? action.getAnnotation(Ajaxed) : null
if (annotation) {
request[GroovyPageLayoutFinder.LAYOUT_ATTRIBUTE] = annotation.layout()
}}
}
}
[/java]
Yes, we can do the map based coding as well, but as the project grows map size will increase which will reduce the readability of the code. Also, we can enhance the annotation based approach by adding some dynamic condition to the annotation, using closure based groovy annotation.
I also checked the time taken to execute this code is not very substantial. To reduce this time, we can create a list of URLs (controller/action) at the start of the application based on annotation and rather than doing the stuff in the filter every time we can read the list.
Don’t you think that it can make your application pretty slow – as it’s checking for all the non-ajaxed requests.
Do you have most of the hits as Ajaxed? And very rare non-ajaxed?
Also, if you have limited actions, those required this kind of behavior – How about if you provide a Map of controller/action (names) in the filter itself. It can figure things faster.