Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement template parts #43

Merged
merged 3 commits into from Jun 18, 2021
Merged

Implement template parts #43

merged 3 commits into from Jun 18, 2021

Conversation

jnthn
Copy link
Member

@jnthn jnthn commented Jun 8, 2021

Template parts are being introduced primarily to ease the common situation where we have sections of a page that need some data to be rendered, and it is inconvenient to pass that in with every call to template. For example, every page may feature an indication of shopping cart size or the name of the currently logged in user in the header.

The special part name MAIN can be used to access the top-level data, which is set as the topic in the template by default. This opens up an alternative pattern for writing more complex templates: pass a Capture as the template data, and have the arguments bound into the MAIN part's parameters.

The part data provider in the template may receive the current request.auth as an argument, and also constrain it, so one could have different part providers for logged in or not logged in, or really any other property reachable via the current auth (which may be a user, a session, etc.)

jnthn added 3 commits June 8, 2021 15:04
The feature is primarily aimed at allowing for data for common elements
of pages to be produced and obtained without needing to explicitly pass
it in to every template call (think a header that has an indication of
if a user is currently logged in, or about their shopping cart content).
A `route` block integration in a subsequent commit will allow for that.
This one gets the basic mechanism in place, testing it by explicitly
providing arguments for the parts.

A further application of this is that the special part MAIN can be used
to obtain the initial argument (or argument capture) for rendering the
template. This will provide a way for folks to bind variables at the
"top level", in more complex cases where the topic approach doesn't
scale so well.
While one can explicitly provide template part data in the `template`
call, it will often be more convenient to avoid repetition and write a
`template-part` provider in the `route` block. This will be called when
the template part is encountered during rendering. It may optionally
have a parameter, which will be bound to `request.auth` so long as the
type matches; said type matching allows for different providers for
logged in or not, or different levels of user, or just to pull data out
of a session (for example, shopping cart content).
@@ -331,8 +332,31 @@ sub template-part-args(Str $name) {
orwith %*CRO-TEMPLATE-EXPLICIT-PARTS{$name} {
$_
}
orwith find-template-part-provider($name) -> &provider {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it doesn't actually make sense, but wouldn't you expect a template part provider to take precedence over a %*CRO-TEMPLATE-EXPLICIT-PARTS kv, and pass the arguments (that is, the explicit parts) to said provider instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In code this is something like:

route {
    template-part 'foo', -> { 'implicit' }
    get -> {
        template 'foo.crotmp', parts => { foo => 'explicit' }
    }
}

Since the explicit one is more local / nested than the part provider, I think it's right this way around.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree with that. The idea I had was that passing arguments to a template-part subroutine might allow for more flexibility:

route {
    template-part 'foo', Str $argument -> { $argument ~~ /^\w+$/ ?? $argument !! $argument.flip }
    get -> {
        template 'foo.crotmp', parts => { foo => 'explicit' }
    }
}

Maybe that's too convoluted, maybe that's not useful, maybe that's confusing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd considered parametric template parts, but decided not to do that for now. It's a step up in power, but also in complexity, and I'm not yet sure if it's justified. Probably one of those things I'd rather see being missed before adding it.

@jnthn jnthn merged commit 89b545d into master Jun 18, 2021
@jnthn jnthn deleted the template-parts branch June 18, 2021 10:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants