Managing form dropdown options at the LP level

This post is an experiment: can a cool technical hack be communicated without extra prose... that is, can I shut up for once? If it doesn’t make sense, ask in the comments! 😉


In Form Editor, just add the field with type Select — options don’t need to be listed there.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta class="mktoString" mktoName="Job Title Option" id="Title-0" default="Select...|">
    <meta class="mktoString" mktoName="Job Title Option" id="Title-1" default="Choice 1">
    <meta class="mktoString" mktoName="Job Title Option" id="Title-2" default="Choice 2">
    <meta class="mktoString" mktoName="Job Title Option" id="Title-3" default="Choice 3">
    <meta class="mktoString" mktoName="Job Title Option" id="Title-4" default="">
    <meta class="mktoString" mktoName="Job Title Option" id="Title-5" default="">
    <title>Test Page</title>
  </head>
  <body>
    <div class="mktoForm" id="exampleForm" mktoName="Example Form">
    </div>
    <datalist id="mktoFormSelectOptions">
      <option label="Title">${Title-0}</option>
      <option label="Title">${Title-1}</option>
      <option label="Title">${Title-2}</option>
      <option label="Title">${Title-3}</option>
      <option label="Title">${Title-4}</option>
      <option label="Title">${Title-5}</option>
    </datalist>
  </body>
</html>
An example Marketo LP template. Note the use of a <datalist> element, which is the perfect choice for storing offline options, while — importantly — correctly encoding values.

mktoString values at the page level become your options. Empty values are skipped. <friendly name>|<server value> syntax (like in Form Editor) is supported.

/**
 * Dynamic <select> options eleement from <datalist>
 * @author Sanford Whiteman
 * @version v1.0 2022-08-21
 * @copyright © 2022 Sanford Whiteman
 * @license Hippocratic 3.0: This license must appear with all reproductions of this software.
 *
 * Prereq: <datalist> structured like:
 *   <datalist id="mktoFormSelectOptions">
 *   <option label="fieldName">Select Fruit...|</option>
 *   <option label="fieldName">Apple|apple</option>
 *   <option label="fieldName">Orange|orange</option>
 *   <option label="fieldName">Pear|pear</option>
 *   <option label="anotherFieldName">Select Sport...|</option>
 *   <option label="anotherFieldName">Basketball|bball</option>
 * etc.
 */
MktoForms2.whenRendered(function(mktoForm){    
    const arrayify = getSelection.call.bind([].slice);
   
    let formEl = mktoForm.getFormElem()[0];

    let allDynamicSelectOptions = document.querySelector("#mktoFormSelectOptions");
   
    let optionsByField = arrayify(allDynamicSelectOptions.options)
    .reduce(function(acc,option){
       if( !(option.label in acc )){
         acc[option.label] = [];       
       }
       if( option.textContent ) {
         acc[option.label].push(option.textContent);
       }
       return acc;
    }, {});
      
    Object.keys(optionsByField)
    .forEach(function(fieldName){       
       let mktoVariableOptions = optionsByField[fieldName];             
       let selectEl = formEl.querySelector("select[name='" + fieldName + "']");
       
       if(selectEl.getAttribute("data-options-managed") != "true" && mktoVariableOptions.length > 0){
          selectEl.setAttribute("data-options-managed","true");
          
          arrayify(selectEl.options)
          .forEach(function(originalOption){
             selectEl.removeChild(originalOption);
          });    

          mktoVariableOptions
          .map(function(mktoVariableOption){
             let newOption = document.createElement("option");
             let optionDescriptor = mktoVariableOption.split("|");

             newOption.textContent = optionDescriptor[0];
             newOption.value = optionDescriptor[optionDescriptor.length == 1 ? 0 : 1];

             return newOption;
          })
          .forEach(function(newOption){
             selectEl.appendChild(newOption);
          });
       }
    })
});
The Forms 2.0 JS to add to your template (recommend a separate <script> tag). Note you don’t configure any fields in the JS, they’re picked up automatically from the <datalist>.

Voilà! Different form variations per LP.