Use a Prebuilt Editor in a Custom Attribute Editor
Create custom attribute editors faster and more efficiently with prebuilt attribute editors. You can use the prebuilt editors as building blocks when you create custom attribute editors.
This table lists the prebuilt editors that are available. We provide multiple IDs for each prebuilt editor so that you can use the style you prefer. All the prebuilt editors open in a separate breakout modal window.
Prebuilt Editor | Purpose | ID | Return Value Type | Return Value Example |
---|---|---|---|---|
Category Picker | Allows merchant to select a category |
sfcc:categoryPicker or
sfcc:category-picker
|
Category ID
<string>
|
|
Link Builder | Builds a link to the element selected by the merchant |
sfcc:linkBuilder or sfcc:link-builder
|
Absolute URL or URL portions
<string |
string[]>
Depending on the link type the user created using the Link Builder, the return value is either a single string or an array of strings. A single string indicates that the value is an absolute URL that can
be used as-is. An array of strings indicates that the URL must be assembled using
the |
or
|
Page Picker | Allows merchant to select a page |
sfcc:pagePicker or sfcc:page-picker
|
Page ID
<string>
|
|
Product Picker | Allows merchant to select a product |
sfcc:productPicker or
sfcc:product-picker
|
Product ID
<string>
|
|
custom
.
selectionTile.json
{
"name": "Category Selection Tile",
"description": "A tile that lets the mercant select a category to display.",
"group": "content",
"attribute_definition_groups": [{
"id": "category",
"name": "Category",
"description": "You can select the category.",
"attribute_definitions": [{
"id": "category",
"name": "Category",
"type": "custom",
"required": true,
"editor_definition": {
"type": "com.sfcc.categoryPicker"
}
}],
categoryPicker.json
{
"name": "Category Editor",
"description": "A prebuilt editor that allows you to select a category.",
"resources": {
"scripts": [
"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js",
"/experience/editors/com/sfcc/categoryPicker_trigger.js"
],
"styles": [
"https://cdnjs.cloudflare.com/ajax/libs/design-system/2.8.3/styles/salesforce-lightning-design-system.min.css",
"/experience/editors/com/sfcc/category.css"
]
}
}
categoryPicker.js
'use strict';
var HashMap = require('dw/util/HashMap');
var Resource = require('dw/web/Resource');
module.exports.init = function (editor) {
// Default values for L10N properties
var l10nDefaults = {
buttonBreakout: 'Select',
titleBreakout: 'Category',
placeholderInput: 'Select the category',
};
// Add some localizations
var localization = Object.keys(l10nDefaults).reduce(function (acc, key) {
acc.put(key, Resource.msg(key, 'experience.editors.sfcc.categoryPicker', l10nDefaults[key]));
return acc;
}, new HashMap());
if (!editor.configuration) {
editor.configuration = new HashMap();
}
editor.configuration.put('localization', localization);
};
On the client side, create a JavaScript file that runs the prebuilt editor, as in this
example. Set the payload ID in the sfcc:breakout
event to the ID of the
prebuilt editor, in this case sfcc:categoryPicker
.
categoryPicker_trigger.js
(() => {
let localization;
let inputEl;
let buttonEl;
β
/**
* This listener subscribes to the creation/initialization event of the sandbox component. This event gets fired when a Page Designer user
* first opens a component of a certain type in the component settings panel (and that component type contains the custom editor).
* **Note:** This event won't fire when the user switches between components of the same type in the canvas. In that case the existing
* attribute editor components will be reused which results in a value update event (`sfcc:value`), therefore no new initialization
* happens.
*/
subscribe('sfcc:ready', ({ value, config, isDisabled, isRequired, dataLocale, displayLocale }) => {
console.log('category-trigger::sfcc:ready', { dataLocale, displayLocale, isDisabled, isRequired, value, config });
β
// Extract data from `config`
({ localization = {} } = config);
β
// Initialize the DOM
const template = obtainTemplate();
const clone = document.importNode(template.content, true);
document.body.appendChild(clone);
β
// Obtain DOM elements and apply event handlers
inputEl = document.querySelector('input');
buttonEl = document.querySelector('button');
buttonEl.addEventListener('click', handleBreakoutOpen);
β
// Update <input> value
inputEl.value = obtainDisplayValue(value);
});
β
/**
* This listener subscribes to external value updates. As stated above, this event also gets fired when the user switches between
* different components of the same type in the canvas. As in that case already existing custom editor instances get reused, it
* technically means that switching between components of the same type is just an external value update.
*/
subscribe('sfcc:value', value => {
console.log('category-trigger::sfcc:value', { value });
β
// Update <input> value
inputEl.value = obtainDisplayValue(value);
});
β
function obtainTemplate() {
const { placeholderInput, buttonBreakout } = localization;
const template = document.createElement('template');
template.innerHTML = `
<div class="slds-grid slds-grid_vertical-align-start">
<div class="slds-col slds-grow">
<input type="text" disabled class="slds-input" placeholder="${placeholderInput}">
</div>
<div class="slds-col slds-grow-none slds-m-left_xx-small">
<button type="button" class="slds-button slds-button_neutral">${buttonBreakout}</button>
</div>
</div>`;
return template;
}
β
function obtainDisplayValue(value) {
return typeof value === 'object' && value != null && typeof value.value === 'string' ? value.value : null;
}
β
function handleBreakoutOpen() {
const { titleBreakout } = localization;
β
emit({
type: 'sfcc:breakout',
payload: {
id: 'sfcc:categoryPicker',
title: titleBreakout
}
}, handleBreakoutClose);
}
β
function handleBreakoutClose({type, value}) {
if (type === 'sfcc:breakoutApply') {
handleBreakoutApply(value);
} else {
handleBreakoutCancel();
}
}
β
function handleBreakoutCancel() {
// Grab focus
buttonEl && buttonEl.focus();
}
β
function handleBreakoutApply(value) {
// Update <input> value
inputEl.value = obtainDisplayValue(value);
β
// Emit value update to the PD host application
emit({
type: 'sfcc:value',
payload: value
});
β
// Grab focus
buttonEl && buttonEl.focus();
}
})();