grails-markup: How to use linkGenerator in included templates
- Dominant language
- Groovy
- Stars
- 2.9k
- Forks
- 975
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 92
Description
## Versions
- grails: 4.0.1
- views-markup: 2.0.0.RC2
## Context
I would like to use markup templates to render html views instead of using gsp pages. When playing a little bit with templates I came up with an example.
- Controller providing some model objects
- Markup view rendered using a custom layout which requires a linkGenerator to **resolve resources** such as css stylesheets and declaring model objects to use
- The same view is including some other templates that require linkGenerator to **create links**
## Controller
```groovy
package org.proto
class SomethingController {
static class Person {
Long id
String name
Integer age
}
def index() {
render(
view: 'index',
model: [
totalCount: 10,
people: [
new Person(id: 1, name: 'John', age: 32),
new Person(id: 2, name: 'Peter', age: 34)
]
]
)
}
}
```
## views/something/index.gml
Declaring model objects in here makes them available to included templates which is the expected behavior. Although I'm not creating any link here, I've checked that it's possible to use Link generator here (via **this.g.link** and **this.g.resource**).
```groovy
import org.proto.SomethingController
model {
Integer totalCount
List people
}
layout 'layouts/custom.gml', title: 'Layout example', bodyContents: contents {
p "Showing $totalCount rows"
table {
include(template: 'something/_thead.gml')
include(template: 'something/_tbody.gml')
}
}
```
## views/layouts/custom.gml (**fails**)
However here, calls to **this.g.resource** fail because linkGenerator is null.
```groovy
yieldUnescaped ''
html(lang:'en') {
head {
meta('http-equiv':'"Content-Type" content="text/html; charset=utf-8"')
link(rel: 'icon', href:"favicon.ico", type:"image/x-ico")
link(
rel: 'stylesheet',
type: 'text/css',
href: this.g.resource(dir: 'assets', file: 'main.css')
)
title(title)
}
body {
header {
h1("$title")
}
section {
bodyContents()
}
footer {
yield "footer"
}
}
}
```
## views/something/_thead.gml
Obviously works as expected because it doesn't use anything special
```groovy
thead {
tr {
th('ID')
th('Name')
th('Description')
}
}
```
## views/something/_tbody.gml (**fails**)
As it happened to **custom.gml** calls to **this.g.link** didn't work either because linkGenerator is null.
```groovy
import org.proto.SomethingController
tbody {
people.each { SomethingController.Person person ->
tr {
td(person.id)
td {
a(href: "${this.g.link(controller: 'plan', action: 'show', id: person.id)}") {
yield "${person.name}"
}
}
td(person.age)
}
}
}
```
## Problem
My first impression is that although you can access to the link generator at the top level view, you can't in any of the included, nested templates.
## Desired behavior
To be capable of accessing main view link generator from any nested/included templates.
Contributor guide
Research direction
Reproduce the example with Grails 4.0.1 and views-markup 2.0.0.RC2 using views/something/index.gml, views/layouts/custom.gml, and views/something/_tbody.gml. Start by tracing how the link generator is available in the top-level view but becomes null in the layout and included template. Done means nested templates can use the main view's link and resource helpers, with tests covering both calls.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- groovy
- Domain
- backend, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100