Skip to main content
Version: 0.5

Customize handler template contexts

This guide covers how to easily customize the template context of handlers involving template renderings and how to add variables to it. Doing so will allow you to leverage custom variables in your handler templates and easily manipulate the appearance and content of your web pages, tailoring them to suit your specific needs and preferences.

Requirements

It is possible to customize the template context used by most handlers involving template renderings. This is the case for:

Customizing the template context of a handler

If your handler adheres to the requirements mentioned above, then the simplest way to customize what variables are made available to the considered template context is to leverage the #before_render callback.

This callback is invoked prior to rendering a template when generating a response that incorporates its content. This means that they can be used to add new variables to the global handler template context so that they become accessible to the template runtime.

For example:

class MyHandler < Marten::Handlers::Template
template_name "app/my_template.html"
before_render :add_foo_to_context

private def add_foo_to_context : Nil
context["foo"] = "bar"
end
end

In the above snippet, a very simple handler (that inherits from the Marten::Handlers::Template generic handler) defines a #before_render callback in which a foo variable is added to the template context.

To exemplify this functionality, let's consider a straightforward scenario involving navigation sections. Typically, it's essential to determine the currently active item within the navigation. This can be effortlessly accomplished by utilizing a dedicated template variable.

For example, let's assume that our navigation template looks something like this:

<nav class="navbar navbar-light">
<div class="container">
<ul class="nav navbar-nav">
<li class="nav-item">
<a class="nav-link{% if nav_bar_item == 'home' %} active{% endif %}" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link{% if nav_bar_item == 'sign_in' %} active{% endif %}" href="{% url 'auth:sign_in' %}">Sign in</a>
</li>
<li class="nav-item">
<a class="nav-link{% if nav_bar_item == 'sign_up' %} active{% endif %}" href="{% url 'auth:sign_up' %}">Sign up</a>
</li>
</ul>
</div>
</nav>

This template utilizes a nav_bar_item variable to determine the currently active navigation bar item and applies a dedicated active CSS class to the corresponding link based on the value of this variable.

In order for this navigation to work as intended, we need to ensure that the applicable handlers define the nav_bar_item template variables. We could utilize the method described previously and simply define a #before_render callback in the handlers that need to define this template variable. A better solution though would be to define a concern module that eases the process of doing this.

For example, we could define a NavBarActiveable module that automatically sets the nav_bar_item template variable based on the value of a class variable that is set by handler classes making use of it:

module NavBarActiveable
macro included
class_getter nav_bar_item : String?

extend NavBarActiveable::ClassMethods

before_render :add_nav_bar_item_to_context
end

module ClassMethods
def nav_bar_item(item : String | Symbol)
@@nav_bar_item = item.to_s
end
end

private def add_nav_bar_item_to_context
context[:nav_bar_item] = self.class.nav_bar_item
end
end

Using this approach, defining the nav_bar_item variable in a handler would be as simple as including the NavBarActiveable module in the handler class and calling the #nav_bar_item method:

class MyHandler < Marten::Handlers::Template
include NavBarActiveable

template_name "app/my_template.html"
nav_bar_item :home
end