
One of the last blog posts (Text and EMail Templates with Handlebars.NET ) was generally about HandleBars.NET - a very popular template engine. This post is about how you can easily implement layouts with Handlebars.
The snippet in the previous post was as follows:
1// MyTemplateProvider.cs
2
3 public MyTemplateProvider()
4 {
5 _handlebars = Handlebars.Create();
6
7 Init(); // Add this
8 }
9
10 private void Init()
11 {
12 // Add Header Template
13 _handlebars.RegisterTemplate("Header_Template", @"<strong>MyCompany - {{Title}}</strong>");
14
15 // Add Footer Template
16 _handlebars.RegisterTemplate("Footer_Template", @"<i>MyCompany - Copyright 2023</i>");
17
18 // Register Welcome Mail
19 _handlebars.RegisterTemplate("WelcomeMail_Template",
20 """
21 <div>
22 <h1>{{>Header_Template}}</h1>
23 <div class="body">
24 <h3>Welcome to our demo {{UserName}}!</h3>
25 <p>Thank you for registering. Have fun!</p>
26 </div>
27 <footer>{{>Footer_Template}}</footer>
28 </div>
29 """);
30 }
As you can see, a template is registered that references other templates - but explicitly. I therefore have to take care of the frame - in this case the header and footer - for my actual content myself. This is not nice and represents a redundancy.
Partial Blocks
Handlebars supports a functionality called Partial Blocks. While simple Partials represent a content block, partial blocks are the construct around it. In Razor, this is comparable to sections. Partial blocks can therefore be used to represent the surrounding content - like our layouts.
1_handlebars.RegisterTemplate("MailLayout", """
2 <div>
3 <h1><strong>MyCompany - {{Title}}</strong></h1>
4 <div class="body">
5 {{> content}}
6 </div>
7 <footer><i>MyCompany - Copyright {{On.Year}}</i></footer>
8 </div>
9 """);
Partial blocks are also registered as templates, but have the special feature that they contain the reserved partial keyword content. This is then replaced by the actual content you have in your template.
The layout can then be referenced in the actual template by specifying the partial block:
1_handlebars.RegisterTemplate("WelcomeMail_Template",
2 """{{#> MailLayout}}
3 <h3>Welcome to our demo {{UserName}}!</h3>
4 <p>Thank you for registering. Have fun!</p>
5 {{/MailLayout}}
6 """);
Full Sample
1using HandlebarsDotNet;
2
3namespace BenjaminAbt.Samples.HandlebarsNET;
4
5internal class Program
6{
7 static void Main(string[] args)
8 {
9 MyTemplateProvider templateProvider = new();
10
11 List<string> userNames = ["Batman", "Robin"];
12 foreach (var userName in userNames)
13 {
14 string text = templateProvider.RenderWelcomeMail(userName);
15
16 Console.WriteLine($"To: {userName}");
17 Console.WriteLine(text);
18 Console.WriteLine("-------------------");
19 }
20 }
21}
22
23// MyTemplateProvider.cs
24public class MyTemplateProvider
25{
26 private readonly IHandlebars _handlebars;
27
28 public MyTemplateProvider()
29 {
30 _handlebars = Handlebars.Create();
31
32 Init(); // Add this
33 }
34
35 private void Init()
36 {
37
38 _handlebars.RegisterTemplate("MailLayout", """
39 <div>
40 <h1><strong>MyCompany - {{Title}}</strong></h1>
41 <div class="body">
42 {{> content}}
43 </div>
44 <footer><i>MyCompany - Copyright {{On.Year}}</i></footer>
45 </div>
46 """);
47
48 // Register Welcome Mail
49 _handlebars.RegisterTemplate("WelcomeMail_Template", InternalRegisterTemplateWithLayout(
50 """
51 <h3>Welcome to our demo {{UserName}}!</h3>
52 <p>Thank you for registering. Have fun!</p>
53 """));
54 }
55
56 private string InternalRegisterTemplateWithLayout(string template)
57 => "{{#> MailLayout}}" + template + "{{/MailLayout}}";
58
59 private HandlebarsTemplate<object, object>? _welcomeTemplate = null;
60 public string RenderWelcomeMail(string userName)
61 {
62 _welcomeTemplate ??= _handlebars.Compile("{{> WelcomeMail_Template}}");
63
64 var data = new
65 {
66 Title = "Welcome!",
67 UserName = userName,
68 On = DateTimeOffset.UtcNow
69 };
70
71 var text = _welcomeTemplate(data);
72 return text;
73 }
74}
Have fun!

Comments