This guide provides some examples of using html templates and handlebars in Foundry VTT dialogs or sheets.
Templates are just html files that can be loaded into Foundry, in lieu of hard-coding all the html within your javascript macro, module, or system.
Examples:
Create in your Data directory a folder to store templates. Don't call it templates, which appears to confuse the caching mechanism. I called mine macro_data
.
Store the below html template in macro_data
.
You are only allowed to load template files with an extension in [html,handlebars,hbs,vue].
Somewhere in your code, you will need to load the templates before using them.
const template_file = "macro_data/TEMPLATE_FILE"
loadTemplates([template_file]);
You will need to either restart your game session to pick up changes to templates, or you can force Foundry to re-load the cache.
const template_file = "macro_data/TEMPLATE_FILE"
delete _templateCache[template_file];
You have various options to use templates in javascript within Foundry. These should function for macros, modules, or systems.
renderTemplate
, passing the template and the data. Then do something with the resulting html.const data_object = {}; // data object to pass to the template
const template_file = "macro_data/TEMPLATE_FILE"; // file path for the template file, from Data directory
const rendered_html = renderTemplate("macro_data/TEMPLATE_FILE", data_object);
Notes:
renderTemplate
calls getTemplate to retrieve a template from the server.getTemplate
in turn compiles the html template using Handlebars.compile
getTemplate
caches the compiled result from Handlebars.compile
.getTemplate
registers the path and compiled result as a handlebars partial.renderTemplate
applies the data to the compiled result to return rendered html.getTemplate
.FormApplication
. You will need to define several methods.class SelectItemDialog extends FormApplication {
constructor(object, options) {
super(object, options)
}
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
template: "macro_data/TEMPLATE_FILE"
});
}
getData(options = {}) {
return super.getData();
}
activateListeners(html) {
super.activateListeners(html);
}
async _updateObject(event, formData) {
return;
}
}
Remember, save the following in the foundry Data folder. For this example, I am saving mine at macro_data/TEMPLATE_FILE
, where TEMPLATE_FILE
is something like basic_template.html
.
<form>
<b>Fixed header</b><br>
{{header}}
<hr>
Fixed content<br>
{{{content}}}
<hr>
Fixed <em>footer</em><br>
{{footer}}
</form>
Notes:
<form>
tag.{{...}}
to pass data; use {{{...}}}
to pass unescaped data (for example, a string variable with html code).<form>
tag is up to you.renderTemplate
and then do something with the resulting htmlconst template_file = "macro_data/TEMPLATE_FILE";
const template_data = { header: "Handlebars header text.",
content: "<em>Handlebars</em> <i>content</i>.",
footer: "Handlebars footer text."};
const rendered_html = await renderTemplate(template_file, template_data);
let d = new Dialog({
title: "MyDialogTitle",
content: rendered_html,
buttons: {
toggle: {
icon: '<i class="fas fa-check"></i>',
label: "Okay",
callback: () => console.log("Okay")
},
},
default: "toggle",
close: html => {
console.log(html);
},
});
d.render(true);
FormApplication
.class myFormApplication extends FormApplication {
constructor(object, options) {
super(object, options);
}
static get defaultOptions() {
return super.defaultOptions;
}
getData(options = {}) {
return super.getData().object; // the object from the constructor is where we are storing the data
}
activateListeners(html) {
super.activateListeners(html);
}
async _updateObject(event, formData) {
return;
}
}
const template_file = "macro_data/TEMPLATE_FILE";
const template_data = { header: "Handlebars header text.",
content: "<em>Handlebars</em> <i>content</i>.",
footer: "Handlebars footer text."};
const my_form = new myFormApplication(template_data, { template: template_file }); // data, options
const res = await my_form.render(true);
If you want to resize the dialog box, you can either hard-code options into your class or pass options dynamically. For example, to have resizable width, replace the my_form definition in the above with the following:
const my_form = new myFormApplication(template_data, { template: template_file,
width: "400",
height: "auto",
resizable: true });