Appearance
Dynamic templates
eWizard.js framework supports dynamic templates—instead of implementing different templates for various platforms, you can create a single template tailored to your unique context.
Dynamic templates change and adapt based on real-time data. Dynamic template ability to adapt is rooted in template parameters that act as metadata for conditional rendering and auto-generated dynamic localization. For this, the following modules are used:
In addition to localization capabilities, dynamic templates support conditional rendering based on dynamic value filtering for applying styles. Conditional rendering uses the same template metadata as localization modules.
Dynamic i18n
Support scope
Dynamic localization is supported in emails only.
To configure dynamic localization, add the dynamic.js file must be placed in /common/i18n/ and place your required localization text in the standard vue-i18n JSON format to your template's /common/i18n/dynamic/ directory.
In JSON files, provide text strings along with the required style classes:
json
{
"eng": {
"textDefault": "<p class='dynamic-text'>Default value from filter</p>",
"text1": "<p class='dynamic-text'>This filter will never be applied</p>",
"text2": "<p class='dynamic-text'>Custom filter (boolean) can be used if the built-in ones are not enough</p>",
"text3": "<p class='dynamic-text'>Reusable filter example 1</p>",
"text4": "<p class='dynamic-text'>Reusable filter example 2</p>",
"text5": "<p class='dynamic-text'>Filtered by theme and country (forteris-light, Global)</p>",
"text6": "<p class='dynamic-text'>Filtered by theme and country (forteris-dynamic, Ukraine)</p>",
"text7": "<p class='dynamic-text'>Filtered by theme and country (forteris-light | forteris-dynamic, France)</p>"
},
"ukr": {
"textDefault": "<p class='dynamic-text'>Значення за замовчуванням з фільтра</p>",
"text1": "<p class='dynamic-text'>Цей фільтр ніколи не буде застосовано</p>",
"text2": "<p class='dynamic-text'>Можна використовувати користувацький фільтр (boolean), якщо вбудованих недостатньо</p>",
"text3": "<p class='dynamic-text'>Приклад багаторазового фільтра 1</p>",
"text4": "<p class='dynamic-text'>Приклад багаторазового фільтра 2</p>",
"text5": "<p class='dynamic-text'>Відфільтровано за темою і країною (forteris-light, Global)</p>",
"text6": "<p class='dynamic-text'>Відфільтровано за темою і країною (forteris-dynamic, Україна)</p>",
"text7": "<p class='dynamic-text'>Відфільтровано за темою і країною (forteris-light | forteris-dynamic, Франція)</p>"
}
}Specify the rendering rules per target system in dynamic.js. For example:
js
import { DynamicFilterKey, EmailSubtype, TargetSystem } from 'ewizardjs';
const reusableFilterExample = {
[DynamicFilterKey.Theme]: ['forteris-light', 'forteris-dynamic'],
[DynamicFilterKey.Country]: 'Global',
};
export default function ({ settings, systemSettings, theme }) {
return {
text1: '#:group1.text1', // Simple string without filters
linkedMessage: 'This is a linked message. It can be any value, that is not a part of localization itself (tokens etc)',
text2: '#:group1.text2', // This text contains text from another i18n key: @:dynamic.linkedMessage
text3: '#:group1.text3', // This text contains text from localization.json file: @:localization.text1
userName: {
defaultValue: '[Insert Name]',
dynamic: [
{
filter: {
[DynamicFilterKey.TargetSystem]: TargetSystem.SFMC,
},
value: '%%replyname%%',
},
{
filter: {
[DynamicFilterKey.TargetSystem]: TargetSystem.Mailchimp,
},
value: '*|LIST:NAME|*',
},
{
filter: {
[DynamicFilterKey.TargetSystem]: TargetSystem.Veeva,
},
value: '{{userName}}',
},
{
filter: {
[DynamicFilterKey.TargetSystem]: TargetSystem.OCE,
},
value: '{{sender.name}}',
},
{
filter: {
[DynamicFilterKey.TargetSystem]: TargetSystem.Adobe,
},
value:
'<span class="acr-block nl-dce-fragment" data-nl-label="Default sender name (DefaultSenderName)" data-nl-name="DefaultSenderName" contenteditable="false">Default sender name</span>',
},
],
},
text4: '#:group1.text4', // Another linked message example: @:dynamic.userName
text5: {
defaultValue: '#:group2.textDefault', // Default value from filter
dynamic: [
{
filter: {
[DynamicFilterKey.Subtype]: [EmailSubtype.Broadcast],
[DynamicFilterKey.TargetSystem]: TargetSystem.Veeva,
},
value: '#:group2.option1', // This filter will not be applied
},
{
filter: {
[DynamicFilterKey.Subtype]: [EmailSubtype.Approved, EmailSubtype.Broadcast],
[DynamicFilterKey.Country]: ['Global', 'Ukraine'],
[DynamicFilterKey.Theme]: ['forteris-light', 'forteris-dynamic'],
[DynamicFilterKey.Custom]: true,
},
value: '#:group2.option2', // When several filters have been passed, the filter with the highest specificity will be applied
},
{
filter: {
[DynamicFilterKey.TargetSystem]: TargetSystem.Adobe,
},
value: '#:group2.option3', // This filter will not be applied
},
],
},
};
}
function customFilterExample() {
return 2 + 2 === 4;
}Export the default function in dynamic.js. You can pass the object with plugins (for example, settings, systemSettings, theme) to the default function. These plugins serve as custom filters, in addition to the built-in ones. The function must return an object in the format localizationKey: value. For example:
js
// The `DynamicFilterKey` enum provided by eWizard.js
import { DynamicFilterKey } from 'ewizardjs';
// An example of the dynamic filtering object that the function must return
const config = {
text1: '#:group1.text1',
text2: {
defaultValue: '#:group3.textDefault',
dynamic: [
{
filter: {
[DynamicFilterKey.Theme]: 'forteris-light',
[DynamicFilterKey.Country]: 'Global',
},
value: '#:group3.text5',
},
{
filter: {
[DynamicFilterKey.Theme]: 'forteris-dynamic',
[DynamicFilterKey.Country]: 'Ukraine',
},
value: '#:group3.text6',
},
{
filter: {
[DynamicFilterKey.Theme]: ['forteris-light', 'forteris-dynamic'],
[DynamicFilterKey.Country]: 'France',
},
value: '#:group3.text7',
},
],
},
}The acceptable value types for the localizationKey are as follows:
String (static or calculated JS, also using plugins passed to the function)
Dynamic filtering object
The object with the filter must be structured as follows:
js
// The `DynamicFilterKey`, `EmailSubtype`, and `TargetSystem`enums provided by eWizard.js
import { DynamicFilterKey, EmailSubtype, TargetSystem } from 'ewizardjs';
// An example of the dynamic filtering object
const config = {
defaultValue: '#:group2.textDefault', // default value if none of the filters pass
dynamic: [ // array with set filter - value
{
filter: { // the filter object itself contains a set of parameters that must match, the parameter can contain either one or an array of several values
[DynamicFilterKey.Subtype]: EmailSubtype.Broadcast,
[DynamicFilterKey.TargetSystem]: TargetSystem.Veeva,
},
value: '#:group2.option1', // the value returned if the filter passes
},
{
filter: {
[DynamicFilterKey.Subtype]: [EmailSubtype.Approved, EmailSubtype.Broadcast],
[DynamicFilterKey.Country]: ['Global', 'Ukraine'],
[DynamicFilterKey.Theme]: ['forteris-light', 'forteris-dynamic'],
[DynamicFilterKey.Custom]: true, // a field containing the boolean result of a custom filter
},
value: '#:group2.option2',
},
{
filter: {
[DynamicFilterKey.TargetSystem]: TargetSystem.Adobe,
},
value: '#:group2.option3',
},
],
};A defaultValue field is required for the dynamic filtering object.
The DynamicFilter class accepts the following object's keys as the built-in filters:
| Key | Description | Applicable to localization | Applicable to themes |
|---|---|---|---|
channel | The omnichannel entity eWizard.js provides the Channel enum values recommended for use as key values. Possible Channel enum values: • Channel.EDETAILER • Channel.EMAIL Channel.SITE • Channel.MESSENGER_AD • Channel.BANNER | No | Yes |
type | Content item type eWizard.js provides the ContentType enum values recommended for use as key values. Possible ContentType enum values: • ContentType.EDETAILER • ContentType.EMAIL • ContentType.SITE • ContentType.MODULE • ContentType.BRIEF • ContentType.MESSENGER_AD • ContentType.BANNER | No | Yes |
subtype | Content item subtype eWizard.js provides the EmailSubtype enum values recommended for use as key values. Possible EmailSubtype enum values: • EmailSubtype.Approved • EmailSubtype.Broadcast • EmailSubtype.Fragment | Yes | Yes |
country | Target country | Yes | Yes |
locale | Localization parameters | No | Yes |
theme | A current theme | Yes | No |
targetSystem | The required target system code eWizard.js provides TargetSystem enum values recommended for use as key values. Possible TargetSystem enum values: • TargetSystem.Adobe • TargetSystem.IQVIA • TargetSystem.Mailchimp • TargetSystem.OCE • TargetSystem.Platforce • TargetSystem.SFDC • TargetSystem.SFMC • TargetSystem.Veeva | Yes | Yes |
custom | The custom filter Accepts boolean values | Yes | Yes |
Filter backward compatibility
For backward compatibility, we recommend using the DynamicFilterKey (enum) exported by the framework.
Implementation details
Filter priority
If template metadata matches several filters, the filter with the largest number of parameters is applied.Filter conflicts
Avoid filters with the same number of parameters that can match the same template metadata to prevent filter conflicts. In this case, with several matching filters, the last filter takes the priority.
Linked messages and dynamic text
Linked messages in text are supported. This allows using dynamic text with CLM-specific syntax—like tokens for email, phone number, name, etc.—as a static string. Also, you can store commonly-used text directly in common localization files and reference them indynamic.js.Reusable filters
Filters can be defined as constants for reuse across multiple instances. For example,javascriptconst userProfileFilter = { [DynamicFilterKey.Country]: ['Global', 'Ukraine'], [DynamicFilterKey.Theme]: ['forteris-light', 'forteris-dynamic'], };Custom filters
Custom filter logic can be extracted into dedicated functions. For better organization and maintainability, these functions can be stored in separate files.Storing localized text
All text that requires localization (translation) must be stored in JSON files within the/common/i18n/dynamic/directory:Use separate JSON files to group related texts.
Nested folders are not supported.
Referencing localized text
To use localized text as a value indynamic.js, stick to the following syntax:#:file_name.key#:is a required prefixfile_nameis the name of the JSON file (e.g.,group1)keyis the specific text key from that JSON file (e.g.,text1)
Example:#:group1.text1
Handling non-localized values
We strongly recommend defining the values that should not be translated (tokens, links, email addresses. etc.) directly within thedynamic.jsfile.
You can then reference these values within your localized JSON files using the linked message syntax:@:dynamic.someKey.Dynamic localization usage
eWizard.js framework adds the prefixdynamicto localization keys described indynamic.js. As a result, for example,text1is transformed intodynamic.text1. These keys are merged into the common localization. It allows using dynamic localization as follows:vue<wiz-text class="text-1" :text="$t('dynamic.text1')"></wiz-text> <wiz-text class="text-2" :text="$t('dynamic.text2')"></wiz-text> <wiz-text class="text-3" :text="$t('dynamic.text3')"></wiz-text>
Dynamic theme values
Filter syntax is similar to localization syntax. It can be used for theme in any content item type. For this, do the following:
Export the required theme as a function and pass it an object containing the settings and
systemSettingsplugins.Import the
DynamicFiltermodule along with the required enum values (e.g.DynamicFilterKey) from the eWizard.js framework.Create a
DynamicFilterinstance and pass thesettingsandsystemSettingsplugins as its parameters (newDynamicFilter(settings, systemSettings)).Use the
resolvemethod from thisDynamicFilterinstance.
Sample templates
An example of a typical dynamic template for the Forteris brand to illustrate dynamic filter usage:
js
import variables from './base/variables.scss';
import fonts from './media/fonts/fonts.scss';
import { emailGlobalConfig, getEmailBlocksConfig } from './email';
import { edetailerGlobalConfig, edetailerBlocksConfig } from './edetailer';
import homeIcon from './edetailer/media/images/components/wiz-menu/home-icon.png';
import piIcon from './edetailer/media/images/components/wiz-menu/pi-icon.png';
import sitemapIcon from './edetailer/media/images/components/wiz-menu/sitemap-icon.svg';
import refIcon from './edetailer/media/images/components/wiz-menu/refs-icon.png';
import menuLogo from './edetailer/media/images/components/wiz-menu/logo.png';
import closeIconSitemap from './edetailer/media/images/components/wiz-sitemap/popup-close-button-icon.svg';
import closeIconRef from './edetailer/media/images/components/wiz-references-popup/popup-close-button-icon.svg';
import closeIcon from './edetailer/media/images/components/wiz-popup/popup-close-button-icon.svg';
import listIcon from './base/media/images/list_icon.png';
export default function({ settings, systemSettings }) {
const images = {
components: {
homeIcon,
piIcon,
sitemapIcon,
refIcon,
menuLogo,
closeIconSitemap,
closeIconRef,
closeIcon,
},
};
const global = {
common: {
...fonts,
variables,
images,
list: {
icon: {
src: listIcon,
},
},
},
email: emailGlobalConfig,
edetailer: edetailerGlobalConfig,
};
const blocks = {
common: {},
email: getEmailBlocksConfig(settings, systemSettings),
edetailer: edetailerBlocksConfig,
};
return {
global,
blocks,
};
};A dynamic template used in email:
js
import { DynamicFilter, DynamicFilterKey } from 'ewizardjs';
// Some email theme content
export function getEmailBlocksConfig(settings, systemSettings) {
const dynamicFilter = new DynamicFilter(settings, systemSettings); // importing filter
return {
// Some blocks config content
ForterisContent04: {
firstTextClass: ['m-p-t-30'],
secondTextClass: ['m-p-b-20'],
},
ForterisDynamic: {
firstTextClass: dynamicFilter.resolve({ // filter usage example
defaultValue: ['bg-green'],
dynamic: [
{
filter: {
[DynamicFilterKey.Country]: 'Ukraine',
},
value: ['bg-blue'],
},
{
filter: {
[DynamicFilterKey.Country]: 'Germany',
},
value: ['bg-black'],
},
],
}),
secondTextClass: dynamicFilter.resolve({
defaultValue: ['bg-green'],
dynamic: [
{
filter: {
[DynamicFilterKey.Country]: 'Ukraine',
},
value: ['bg-yellow'],
},
{
filter: {
[DynamicFilterKey.Country]: 'Germany',
},
value: ['bg-red'],
},
],
}),
thirdTextClass: dynamicFilter.resolve({
defaultValue: ['bg-green'],
dynamic: [
{
filter: {
[DynamicFilterKey.Country]: 'Ukraine',
},
value: ['bg-transparent'],
},
{
filter: {
[DynamicFilterKey.Country]: 'Germany',
},
value: ['bg-yellow'],
},
],
}),
},
};
};Keys of the filtering object are a set of built-in filters in the DynamicFilter class and are as follows:
| Key | Description |
|---|---|
channel | An omnichannel entity |
type | A content item type |
subtype | A content item subtype |
country | A target country |
locale | Localization parameter |
theme | A current theme Doesn't relate to themes |
targetSystem | A target CLM code |
custom | A custom filter |