Template manages template definitions (TemplateName, LayoutHTML, customer key, etc.). Use Retrieve with optional QueryAllAccounts: true to search across accessible accounts.

Methods

Method Returns Description
Template.Init(key) TemplateInstance Bind by external key
Template.Add(properties) string Create a template
Template.Retrieve(filter) object[] Query templates
<TemplateInstance>.Update(properties) string Update the initialized template

Template.Init

Initializes a Template instance for the given external key.

Syntax

Template.Init(key)

Parameters

Name Type Required Description
key string Yes External key

Return value

TemplateInstance

Examples

Platform.Load("core", "1");
var t = Template.Init("myTemplate");
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: Template.Init(key)
 *
 * CloudPage GET context. Proves:
 *   1. Template requires the Core load and is then an object exposing the
 *      documented statics Init, Add and Retrieve.
 *   2. There is no static Update / Remove — those are instance methods only.
 *   3. Init(key) returns a TemplateInstance whose members are Update and
 *      Remove (each typeof "function"). Remove is present on the stub but
 *      is a no-op at runtime (cleanup uses WSProxy — see add/retrieve/
 *      instance-update scripts); this chapter only asserts the shape.
 *   4. The instance carries NO readable template fields (CustomerKey,
 *      TemplateName, LayoutHTML, ID read back undefined) — Init binds a
 *      key, it does not fetch. Read fields via Template.Retrieve.
 *   5. A nonsense key yields an indistinguishable stub.
 *   6. The exact example shape on the page (Init("myTemplate")) runs.
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function typeOf(fn) {
    try { return "" + fn(); } catch (ex) { return "THREW"; }
}
function invocationResult(fn) {
    try { fn(); return "returned"; } catch (ex) { return "threw"; }
}

assert("typeof Template is object", typeOf(function () { return typeof Template; }), "object");
assert("typeof Template.Init is function", typeOf(function () { return typeof Template.Init; }), "function");
assert("typeof Template.Add is function", typeOf(function () { return typeof Template.Add; }), "function");
assert("typeof Template.Retrieve is function", typeOf(function () { return typeof Template.Retrieve; }), "function");
assert("Template.Update is not a static", typeOf(function () { return typeof Template.Update; }), "undefined");
assert("Template.Remove is not a static", typeOf(function () { return typeof Template.Remove; }), "undefined");

var myTpl = Template.Init("ssjs-guide-ts-tpl-init");
assert("typeof Template.Init(key) is object", typeof myTpl, "object");
assert("typeof instance.Update is function", typeof myTpl.Update, "function");
assert("typeof instance.Remove is function", typeof myTpl.Remove, "function");
assert("instance has no Add", typeof myTpl.Add, "undefined");
assert("instance has no Retrieve", typeof myTpl.Retrieve, "undefined");
assert("instance exposes exactly Remove+Update", "" + Stringify(myTpl), '{"Remove":"function","Update":"function"}');

assert("instance.CustomerKey is undefined (Init does not fetch)", typeof myTpl.CustomerKey, "undefined");
assert("instance.TemplateName is undefined (Init does not fetch)", typeof myTpl.TemplateName, "undefined");
assert("instance.LayoutHTML is undefined (Init does not fetch)", typeof myTpl.LayoutHTML, "undefined");
assert("instance.ID is undefined (Init does not fetch)", typeof myTpl.ID, "undefined");

var bogus = Template.Init("ssjs-guide-no-such-tpl-zzz");
assert("Init(nonsense key) still returns an object", typeof bogus, "object");
assert("Init(nonsense key) exposes Update", typeof bogus.Update, "function");
assert("Init(nonsense key) stub is indistinguishable", ("" + Stringify(bogus)) === ("" + Stringify(myTpl)) ? "true" : "false", "true");
assert("page example: Init('myTemplate') returns", invocationResult(function () { return Template.Init("myTemplate"); }), "returned");
</script>


Template.Add

Creates a new template with the specified properties.

Syntax

Template.Add(properties)

Parameters

Name Type Required Description
properties object Yes CustomerKey, TemplateName, LayoutHTML, …

Return value

"OK" on success; "Error" on failure (does not throw).

Examples

Platform.Load("core", "1");
var myTemp = {
    CustomerKey: "test_template",
    TemplateName: "SSJS Test Template",
    LayoutHTML: "this is some HTML"
};
var status = Template.Add(myTemp);
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: Template.Add(properties)
 *
 * CloudPage GET context. Proves:
 *   1. Template.Add is a function taking one properties object.
 *   2. Add(properties) with the page example fields (CustomerKey,
 *      TemplateName, LayoutHTML) returns the string "OK" and creates a
 *      retrievable template.
 *   3. Failures return the string "Error" and do NOT throw (Add() /
 *      Add({})) — callers must test the return value (DEV vs older catalog
 *      prose that claimed a throw).
 *   4. Init instance has no Add (Add is static).
 *   5. Instance.Remove is a no-op: after Remove the row still exists;
 *      cleanup uses WSProxy deleteItem and re-counts to 0.
 *
 * FIXTURE: ssjs-guide-ts-tpl-add — created and removed; orphan re-count 0.
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function invocationResult(fn) {
    try { fn(); return "returned"; } catch (ex) { return "threw"; }
}
function countByKey(key) {
    var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
    return rows && rows.length ? rows.length : 0;
}
function cleanupByKey(key) {
    var api = new Script.Util.WSProxy();
    var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
    var i;
    for (i = 0; i < (rows && rows.length ? rows.length : 0); i++) {
        api.deleteItem("Template", { CustomerKey: "" + rows[i].CustomerKey, ID: rows[i].ID });
    }
    return countByKey(key);
}

var KEY = "ssjs-guide-ts-tpl-add";
assert("orphan cleanup pre-count is 0", "" + cleanupByKey(KEY), "0");

assert("typeof Template.Add is function", typeof Template.Add, "function");
assert("Init instance has no Add (Add is static)", typeof Template.Init(KEY).Add, "undefined");

var status = null;
assert("Add(properties) does not throw", invocationResult(function () {
    status = Template.Add({
        CustomerKey: KEY,
        TemplateName: "SSJS Test Template",
        LayoutHTML: "this is some HTML"
    });
}), "returned");
assert("Add returns the string \"OK\"", "" + status, "OK");
assert("Add result typeof is string", typeof status, "string");
assert("the template exists after Add", "" + countByKey(KEY), "1");

assert("DEV Add() with no argument returns \"Error\" (does not throw; older catalog: throws)", "" + Template.Add(), "Error");
assert("Add() with no argument does NOT throw", invocationResult(function () { return Template.Add(); }), "returned");
assert("DEV Add({}) returns \"Error\" (does not throw; older catalog: throws)", "" + Template.Add({}), "Error");

/* Prove instance.Remove is a no-op so cleanup cannot rely on it. */
var removeRet = Template.Init(KEY).Remove();
assert("DEV instance.Remove returns undefined (does not delete)", typeof removeRet, "undefined");
assert("DEV instance.Remove left the row in place", "" + countByKey(KEY), "1");

assert("fixture cleanup via WSProxy re-count is 0", "" + cleanupByKey(KEY), "0");
</script>


Template.Retrieve

Queries templates matching the given filter. Pass { Filter: { Property, SimpleOperator, Value }, QueryAllAccounts: true } to search all accessible accounts.

Syntax

Template.Retrieve(filter)

Parameters

Name Type Required Description
filter object Yes WSProxy-style filter (optionally with QueryAllAccounts)

Return value

object[]

Examples

Platform.Load("core", "1.1.5");
var getTemplate = Template.Retrieve({
    Property: "CustomerKey",
    SimpleOperator: "equals",
    Value: "MyTemplate"
});
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: Template.Retrieve(filter)
 *
 * CloudPage GET context. Proves:
 *   1. Retrieve is a function taking one PascalCase WSProxy-style filter.
 *   2. On a match the result reports as [object Array], exposes .length,
 *      and is not a JS Array (instanceof Array is false).
 *   3. A matched row exposes readable CustomerKey, TemplateName,
 *      LayoutHTML and numeric ID.
 *   4. On no match the same array-like shape is returned with length 0
 *      and Stringify "[]".
 *   5. The documented CustomerKey filter resolves the owned fixture.
 *   6. The page's QueryAllAccounts wrapper shape
 *      { Filter, QueryAllAccounts: true } is accepted and returns the
 *      same array-like collection.
 *
 * FIXTURE: creates ssjs-guide-ts-tpl-retrieve and removes it at the end.
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function countByKey(key) {
    var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
    return rows && rows.length ? rows.length : 0;
}
function cleanupByKey(key) {
    var api = new Script.Util.WSProxy();
    var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
    var i;
    for (i = 0; i < (rows && rows.length ? rows.length : 0); i++) {
        api.deleteItem("Template", { CustomerKey: "" + rows[i].CustomerKey, ID: rows[i].ID });
    }
    return countByKey(key);
}

var KEY = "ssjs-guide-ts-tpl-retrieve";
cleanupByKey(KEY);
Template.Add({
    CustomerKey: KEY,
    TemplateName: "SSJS Guide TS Template Retrieve",
    LayoutHTML: "retrieve probe HTML"
});

assert("typeof Template.Retrieve is function", typeof Template.Retrieve, "function");

var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: KEY });
assert("typeof the matched result is object", typeof rows, "object");
assert("the matched result reports as [object Array]", Object.prototype.toString.call(rows), "[object Array]");
assert("the matched result exposes a numeric .length", typeof rows.length, "number");
assert("the matched result has exactly one row", "" + rows.length, "1");
assert("instanceof Array is false (engine-wide host-array quirk)", rows instanceof Array ? "true" : "false", "false");
assert("matched row CustomerKey equals the filter value", "" + rows[0].CustomerKey, KEY);
assert("matched row TemplateName is a string", typeof rows[0].TemplateName, "string");
assert("matched row LayoutHTML is a string", typeof rows[0].LayoutHTML, "string");
assert("matched row ID is a number", typeof rows[0].ID, "number");
assert("matched LayoutHTML equals the Add payload", "" + rows[0].LayoutHTML, "retrieve probe HTML");

var empty = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: "ssjs-guide-no-such-tpl-zzz" });
assert("empty result reports as [object Array]", Object.prototype.toString.call(empty), "[object Array]");
assert("empty result length is 0", "" + empty.length, "0");
assert("empty result Stringify is []", "" + Stringify(empty), "[]");
assert("workaround: guard with rows && rows.length before indexing", (rows && rows.length) ? "true" : "false", "true");

var qaa = Template.Retrieve({
    Filter: { Property: "CustomerKey", SimpleOperator: "equals", Value: KEY },
    QueryAllAccounts: true
});
assert("QueryAllAccounts wrapper reports as [object Array]", Object.prototype.toString.call(qaa), "[object Array]");
assert("QueryAllAccounts wrapper exposes numeric .length", typeof qaa.length, "number");
assert("QueryAllAccounts wrapper finds the fixture", qaa.length >= 1 ? "true" : "false", "true");

assert("fixture cleanup via WSProxy re-count is 0", "" + cleanupByKey(KEY), "0");
</script>


<TemplateInstance>.Update

Updates the initialized template with the given properties.

Syntax

<TemplateInstance>.Update(properties)

Parameters

Name Type Required Description
properties object Yes Attributes to change

Return value

"OK" on success; "Error" on failure (does not throw).

Examples

Platform.Load("core", "1.1.5");
var myTemplate = Template.Init("myTemplateCK");
var status = myTemplate.Update({ TemplateName: "Edited Template" });
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: <TemplateInstance>.Update(properties)
 *
 * CloudPage GET context. Proves:
 *   1. Update is an instance method (typeof "function") on Template.Init.
 *   2. Update(properties) returns the string "OK" on success.
 *   3. The page example shape Update({ TemplateName }) succeeds and the
 *      new name is visible via Retrieve.
 *   4. A repeated Update on the same key still returns "OK".
 *   5. Negative case: Update on a nonexistent key returns "Error" (does
 *      not throw) — callers must test the return value (DEV vs older
 *      catalog prose that claimed a throw).
 *
 * FIXTURE: creates ssjs-guide-ts-tpl-update and removes it at the end.
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function invocationResult(fn) {
    try { fn(); return "returned"; } catch (ex) { return "threw"; }
}
function countByKey(key) {
    var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
    return rows && rows.length ? rows.length : 0;
}
function cleanupByKey(key) {
    var api = new Script.Util.WSProxy();
    var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
    var i;
    for (i = 0; i < (rows && rows.length ? rows.length : 0); i++) {
        api.deleteItem("Template", { CustomerKey: "" + rows[i].CustomerKey, ID: rows[i].ID });
    }
    return countByKey(key);
}

var KEY = "ssjs-guide-ts-tpl-update";
cleanupByKey(KEY);
Template.Add({
    CustomerKey: KEY,
    TemplateName: "SSJS Guide TS Template Update",
    LayoutHTML: "update probe HTML"
});

var myTemplate = Template.Init(KEY);
assert("typeof instance.Update is function", typeof myTemplate.Update, "function");

var status = myTemplate.Update({ TemplateName: "Edited Template" });
assert("page example: Update({TemplateName}) returns \"OK\"", "" + status, "OK");
assert("Update returns a string", typeof status, "string");

var after = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: KEY });
assert("Retrieve shows the updated TemplateName", "" + after[0].TemplateName, "Edited Template");
assert("a repeated Update on the same instance still returns \"OK\"", "" + myTemplate.Update({ LayoutHTML: "second update HTML" }), "OK");
assert("a freshly initialized instance for the same key also returns \"OK\"", "" + Template.Init(KEY).Update({ LayoutHTML: "third update HTML" }), "OK");

assert("DEV Update on a nonexistent key returns \"Error\" (does not throw; older catalog: throws)", "" + Template.Init("ssjs-guide-no-such-tpl-zzz").Update({ TemplateName: "x" }), "Error");
assert("Update on a nonexistent key does NOT throw", invocationResult(function () { return Template.Init("ssjs-guide-no-such-tpl-zzz").Update({ TemplateName: "x" }); }), "returned");

assert("fixture cleanup via WSProxy re-count is 0", "" + cleanupByKey(KEY), "0");
</script>