Client-Side JavaScript and CSS for the Control

Put the client-side JavaScript files and CSS resources required to run the custom control in 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 control.

For example, let's say the meta definition file and script file for the control are at the following location:

mycartridge/cartridge/experience/editors/com/sfcc/magical.json

mycartridge/cartridge/experience/editors/com/sfcc/magical.js

Put the JavaScript and CSS files here:

mycartridge/cartridge/static/default/experience/editors/com/sfcc

This example of a client-side JavaScript file, named magical_editor.js, uses a <select> element to display data and interact with the user. The example displays three sets of unicorn types inside of <optgroup> elements. The three different types correspond to the three different sources from which the unicorns were passed to the control:

In this example, the control subscribes to the event sfcc:ready. As soon as this event is emitted by the host, the control 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 control sends the sfcc:value event to inform the host.

magical_editor.js
(() => {
  const shopApiBase = `https://${location.hostname}/s/SiteGenesis/dw/shop/v19_3/`;
  const clientId = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa';
 
  const fetchOcapiGET = async () => {
    const response = await fetch(`${shopApiBase}product_search?q=shoes&count=5&client_id=${clientId}`);
    return response.json();
  };
 
  const obtainTemplate = ({ placeholder, description, group1, group2, group3 }) => {
    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>
      <optgroup label="${group3}" disabled></optgroup>
    </select>
  </div>
</div>`;
    return template;
  };
 
  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 productsResponse = await fetchOcapiGET();
    const productLabels = productsResponse.hits.map(hit => `${hit.product_id} - ${hit.product_name}`);
    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);
 
    // Set <options> from OCAPI response
    setOptions(productLabels, optgroupEls[2], selectedValue);
 
    // Apply change listener
    selectEl.addEventListener('change', event => {
      const val = event.target.value;
      emit({
        type: 'sfcc:value',
        payload: val ? { value: val } : null
      });
    });
  });
 
  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);
    });
  }
})();