Applying layout to template at Runtime in Grails Application

16 / Mar / 2014 by Uday Pratap Singh 2 comments

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.


So to fix this issue we need to apply the layout at runtime and its pretty easy in grails to do this, by writing the following code

request[GroovyPageLayoutFinder.LAYOUT_ATTRIBUTE] = "main"

To make this more generic I created an annotation which will be applied to the Ajax actions. I also updated the filter to apply layout based on request xhr and the annotation is applied to action or not

  • Create annotation in src/groovy folder
    package com.sony.common.annotation
    
    import 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"
    
    }
    
  • Apply annotation to the controller method
    @Ajaxed()
        def searchPlayers(PlayerSearchCO playerSearchCO) {
            List<Player> players = searchService.search(playerSearchCO)
            render(template: 'players', model: [players: players, teamParticipant: playerSearchCO.teamParticipant])
        }
    
  • Add Filter to apply layout
    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()
                        }
    
                    }
                }
            }
    

and that’s it. Now your view will look something like this

FOUND THIS USEFUL? SHARE IT

comments (2)

  1. Uday Pratap Singh Post author

    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.

    Reply
  2. Adam

    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.

    Reply

Leave a comment -