apache / apache/grails-core

grails-markup: How to use linkGenerator in included templates

Open
#14,279 1 comment 0 reactions 0 assignees View on GitHub
relates-to: grails-markup relates-to: grails-views
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.