This sample demonstrates how to use the templatesConfig option to configure a templates gallery for the SpreadJS Designer.
By setting the templatesConfig property in the Designer configuration, you can specify a URL pointing to a template configuration JSON file. The Designer will load the default template (the first one in the list) during initialization and when the user performs a "New" (Reset) operation. Multiple templates with thumbnails are displayed in the "New" tab of the File Menu, allowing users to quickly create workbooks from pre-defined templates.
The configuration file contains an array of ITemplateConfig objects with the following structure:
name: The template display name.
data (optional): A string URL (the Designer will fetch and auto-detect the format by extension) or an Object (treated as pre-loaded Workbook JSON). If omitted, the template is considered blank.
thumbnail (optional): An image URL or base64 string. If omitted, the default blank template thumbnail is used.
Supported template formats include .ssjson, .sjs, .xlsx, .xltx, .xlsm, and .xltm.
Example templatesConfig.json:
Since the default template is loaded asynchronously after the Designer is constructed, any workbook operations performed immediately after new Designer() may be overwritten when the template finishes loading. Use designer.waitForDefaultTemplateLoaded() method to ensure the template has been fully applied before operating on the workbook.
const resources = {
tips: 'Please click the "File" button in the upper-left corner to access the File menu, then select the "New" tab to view templates gallery.',
}
window.onload = async function () {
let designer = new GC.Spread.Sheets.Designer.Designer("dss", { templatesConfig: '$DEMOROOT$/spread/source/data/templates.json' });
await designer.waitForDefaultTemplateLoaded();
let spread = designer.getWorkbook();
spread.getActiveSheet().setValue(1, 1, resources.tips);
}
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta name="spreadjs culture"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-designer/styles/gc.spread.sheets.designer.light.min.css">
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-shapes/dist/gc.spread.sheets.shapes.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-charts/dist/gc.spread.sheets.charts.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-print/dist/gc.spread.sheets.print.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-barcode/dist/gc.spread.sheets.barcode.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-pdf/dist/gc.spread.sheets.pdf.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-pivot-addon/dist/gc.spread.pivot.pivottables.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-slicers/dist/gc.spread.sheets.slicers.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-tablesheet/dist/gc.spread.sheets.tablesheet.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-formula-panel/dist/gc.spread.sheets.formulapanel.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-io/dist/gc.spread.sheets.io.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-designer-resources-en/dist/gc.spread.sheets.designer.resource.en.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-designer/dist/gc.spread.sheets.designer.all.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/js/designer/license.js" type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
<link href="./styles.css" rel="stylesheet" type="text/css" />
</head>
<body style="margin:0;padding:0">
<div id="dss" style="width:100vw;border:1px solid darkgray"></div>
</body>
</html>
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#dss {
height: 100%;
}
function FileTemplateSelector() {
GC.Spread.Sheets.Designer.AtomicComponentBase.call(this, ...arguments);
this.selectedTemplate = null;
};
FileTemplateSelector.prototype = new GC.Spread.Sheets.Designer.AtomicComponentBase();
FileTemplateSelector.prototype.getTemplate = function () {
return `
<div class="template-selector">
<div class="templates-grid">
</div>
</div>`;
}
FileTemplateSelector.prototype._generateTemplateItem = function (template) {
let div = document.createElement("div");
div.setAttribute("key", template.id);
div.className = "template-card";
div.innerHTML = `
<div class="template-preview">
<div class="template-image-placeholder">
<div class="preview-content">
<div class="simple-preview" style="background: url(${template.image}) no-repeat center center; background-size: cover;">
<div class="preview-icon"></div>
</div>
</div>
</div>
</div>
<div class="template-info">
<h3 class="template-title">${template.title}</h3>
</div>
`;
return div;
}
FileTemplateSelector.prototype.handleTemplateClick = function (e) {
const templateCard = e.target.closest(".template-card");
if (templateCard) {
this.selectedTemplate = templateCard.getAttribute("key");
this.raiseValueChanged()
}
}
FileTemplateSelector.prototype.onMounted = function (host) {
host.querySelector(".templates-grid").addEventListener("click", this.handleTemplateClick.bind(this));
}
FileTemplateSelector.prototype.onRaiseValueChanged = function () {
this.onRaiseValueChanged();
}
FileTemplateSelector.prototype.onValueChanged = function (prevValue, nextValue, host) {
let templates = nextValue;
if (templates && Array.isArray(templates) && templates.length > 0) {
host.querySelector(".templates-grid").innerHTML = "";
templates.forEach(template => {
let templateItem = this._generateTemplateItem(template);
host.querySelector(".templates-grid").appendChild(templateItem);
})
}
}
FileTemplateSelector.prototype.updateValue = function (host) {
//return the select template;
return this.selectedTemplate;
}
FileTemplateSelector.prototype.onDestroy = function (host) {
host.querySelector(".templates-grid").removeEventListener("click", this.handleTemplateClick.bind(this));
}
// Register Custom Component to Designer
GC.Spread.Sheets.Designer.Designer.RegisterComponent("FileTemplateSelector", FileTemplateSelector);
var fileMenuTemplate = GC.Spread.Sheets.Designer.getTemplate(
GC.Spread.Sheets.Designer.TemplateNames.FileMenuPanelTemplate
);
addCustomItem(fileMenuTemplate);
GC.Spread.Sheets.Designer.registerTemplate(
GC.Spread.Sheets.Designer.TemplateNames.FileMenuPanelTemplate,
fileMenuTemplate
);
function addCustomItem(template) {
//add Template to the left menu list;
template.content[0].children[0].children[0].children[0].children[1].items.push({ text: "Template", value: "Template" });
//add Template page to the right container;
var listDisplayContainer = template.content[0].children[0].children[1];
listDisplayContainer.children.push({
type: "Container",
visibleWhen: "activeCategory_main=Template",
children: [
{
type: 'TextBlock',
margin: '50px 0 15px 50px',
style: 'font-size:36px;',
text: 'Templates'
},
{
type: "FileTemplateSelector",
bindingPath:"customTemplates"
}
],
attributes:[
{key: 'data-activeCategory_main', value: 'Template'}
]
});
}