Client-Side JavaScript and CSS for a Custom Attribute Editor
Put the client-side JavaScript files and CSS resources required to run the custom attribute editor in the static/default directory of the custom cartridge at a location that corresponds to the location of the meta definition file and script file for the editor.
For example, let's say the meta definition file and script file for the custom attribute editor are in the following location:
my_bm_cartridge/cartridge/experience/editors/com/sfcc/magical.json
my_bm_cartridge/cartridge/experience/editors/com/sfcc/magical.js
Put the JavaScript and CSS files here:
my_bm_cartridge/cartridge/static/default/experience/editors/com/sfcc
This example of a client-side JavaScript file uses a <select>
element to
display data and interact with the user. The example displays two sets of unicorn types inside
of <optgroup>
elements. The two different types correspond to the two
different sources from which the unicorns were passed to the editor.
-
group1
βUnicorn types entered into theconfiguration
element of theeditor_definition
for the attribute in the component's meta definition file. -
group2
βUnicorn types passed to the custom attribute editor from theinit
function of the editor's script file.
In this example, the custom attribute editor subscribes to the event
sfcc:ready
. As soon as this event is emitted by the host, the editor
initializes its DOM (Document Object Model) using configuration and localization information
from the init
function of the server-side script file and assigning the
unicorns to their appropriate <optgroup>
. When the user changes the value
of the <select>
element, the editor sends the sfcc:value
event to inform the host.
magical_editor.js
(() => {
subscribe('sfcc:ready', async ({ value, config, isDisabled, isRequired, dataLocale, displayLocale }) => {
console.log('sfcc:ready', dataLocale, displayLocale, value, config);
const selectedValue = typeof value === 'object' && value !== null && typeof value.value === 'string' ? value.value : null;
const { options = {}, localization = {} } = config;
let isValid = true;
// Append basic DOM
const template = obtainTemplate(localization);
const clone = document.importNode(template.content, true);
document.body.appendChild(clone);
// Set props
const selectEl = document.querySelector('select');
selectEl.required = isRequired;
selectEl.disabled = isDisabled;
// Set <options> from JSON config
const optgroupEls = selectEl.querySelectorAll('optgroup');
setOptions(options.config || [], optgroupEls[0], selectedValue);
// Set <options> from init()
setOptions(options.init || [], optgroupEls[1], selectedValue);
// Apply change listener
selectEl.addEventListener('change', event => {
const val = event.target.value;
emit({
type: 'sfcc:value',
payload: val ? { value: val } : null
});
});
});
function obtainTemplate({ placeholder, description, group1, group2 }) {
const template = document.createElement('template');
template.innerHTML = `
<div style="display: flex; justify-content: space-between; align-items: center;">
<div class="slds-select_container" title="${description}">
<select class="slds-select">
<option value="">-- ${placeholder} --</option>
<optgroup label="${group1}"></optgroup>
<optgroup label="${group2}"></optgroup>
</select>
</div>
</div>`;
return template;
}
function setOptions(options, optgroupEl, selectedValue) {
options.forEach(option => {
const optionEl = document.createElement('option');
optionEl.text = option;
optionEl.value = option;
optionEl.selected = option === selectedValue;
optgroupEl.appendChild(optionEl);
});
}
})();