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
Conversation
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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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 aCapture
as the template data, and have the arguments bound into theMAIN
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 currentauth
(which may be a user, a session, etc.)