TagLib made in Grails is plain simple closure. Yet you can rely on implicit `pageScope` variable to do the trick.
Or fall back to JSP taglibs.
https://grails.github.io/grails-doc/latest/ref/Tag%20Libraries/pageScope.htmlBesides example code at that page I can think of some variations, all using the same method.
1) push/pop from stack
def stack =
pageScope._tagStack ?: []
// ...
// ... find parent, sanity check, etc
stack.
push(object_that_defines_this_tag)
try {
body() // <-- process child elements
} finally {
stack.
pop()
}
Thus, all logic is around that stack. A child access it to fetch list/data of ancestors.
To protect stack from damage you can clone it before invoking body() and restore after that.
Even better, use utility class/methods that prevent your from copy-paste that code in all related tags.
2) expose parent object that tracks hierarchy
So you can hide assertion checks and other logic in it.
And control whether a child should know more than its direct parent.
def parent = pageScope._parent
// ...
// ... parent may know grant parent and so on...
def me = parent.createChild()
// substitute active parent reference for my children
pageScope._parent =
metry {
body() // <-- go deeper
} finally {
// restore real parent for next sibling, if any
pageScope._parent =
parent}
3) gather children in list
In some cases you may need to postpone execution of body() of children and delegate that to their parent/ancestor.
At the moment of execution each child may know what siblings were before one but knows nothing about what come after.
For example, to divide grid row equally among 1/2/3/4 columns.
While some of them may be omitted with <g:if test="..."></g:if>.
Until you gather all columns you have no idea which bootstrap class (col-md-#) is required.
Here parent can add some list in pageScope:
pageScope.
_columns = []
body()
// ... process pageScope._columns later
Where each child have to place reference on it's body variable instead of invoking it:
pageScope.
_columns << bodyNote that all other output inside parent-tag but outside of selected children will be omitted.
Or replace `body()` with `out << body()` at parent and have a nice mix.