title: Dynamic selectone in alfresco share
body: <p>For a form in Alfresco share, I want a dropdown box that is filled with custom options depending on the value of a field earlier up in the form.</p>
  
  <p>My form would have at least two fields. The first one a textbox, where a unique code must be entered. When that is done, the second one, a select box, must load it's options using the entered code.</p>
  
  <p>The data backing this requirement is stored in a Data list. I have also made it available through a webscript (along the lines of <code>/getOptions/{uniqueCode</code>, returning a JSON array of the valid options.</p>
  
  <p>Now, I am a bit stuck on how to build the part of the form that will watch for status changes on the code textfield, and reload the dropdown box. I can think of some javascript, but I don't even know where to start changing/adding files.</p>
  
  <p>I've looked through the <code>FDK</code>, where I found the selectone ftl. Unfortunately, this supports only fixed options.</p>
  
  <p><strong>My implementation based on my chosen answer</strong></p>
  
  <p>This is very similar to what I was already doing, I had hoped to be able to do this on the server side, without including the extra round-trip. So far, this is the best I have though.</p>
  
  <p><strong><code>share-config-custom.xml</code></strong></p>
  
  <p>I define the form here, and point the property I want to be my selectone to my own custom field template. I pass a parameter <code>ds</code> to it, <code>dataSource</code>, which holds the path to my webscript.</p>
  
  <pre><code>&lt;config evaluator="node-type" condition="my:contentType"&gt;
        &lt;forms&gt;
           &lt;form&gt;
              &lt;field-visibility&gt;
                 &lt;show id="my:code" /&gt;
                 &lt;show id="my:description" /&gt;
              &lt;/field-visibility&gt;
              &lt;appearance&gt;
                 &lt;set id="general" appearance="bordered-panel" label="General" /&gt;
                 &lt;field id="my:description" set="general"&gt;
                     &lt;control template="/org/alfresco/components/form/controls/customSelectone.ftl"&gt;
                         &lt;control-param name="ds"&gt;/alfresco/service/mark/cache/options&lt;/control-param&gt;
                     &lt;/control&gt;
                 &lt;/field&gt;
              &lt;/appearance&gt;
          &lt;/form&gt;
      &lt;/forms&gt;
  </code></pre>
  
  <p></p>
  
  <p><strong>customSelectone.ftl</strong></p>
  
  <p>My custom ftl has three major steps. First, it receives the ftl parameter I passed from share config custom and assigns it to a local variable. Then it places a html <code>&lt;select&gt;</code>box as a field, and finally, it executes a call to my webscript for the possible options.</p>
  
  <p>Parameter</p>
  
  <p><code>&lt;#if field.control.params.ds?exists&gt;&lt;#assign ds=field.control.params.ds&gt;&lt;#else&gt;&lt;#assign ds=''&gt;&lt;/#if&gt;</code></p>
  
  <p>html</p>
  
  <pre><code>&lt;style type="text/css"&gt;
  #${fieldHtmlId}-AutoComplete {
      width:${width}; /* set width here or else widget will expand to fit its container */
      padding-bottom:2em;
  }
  &lt;/style&gt;
  
  &lt;div class="form-field"&gt;
     &lt;#-- view form --&gt;
     &lt;#if form.mode == "view"&gt;
        &lt;div class="viewmode-field"&gt;
           &lt;#if field.mandatory &amp;&amp; !(field.value?is_number) &amp;&amp; field.value == ""&gt;
              &lt;span class="incomplete-warning"&gt;&lt;img src="${url.context}/components/form/images/warning-16.png" title="${msg("form.field.incomplete")}" /&gt;&lt;span&gt;
           &lt;/#if&gt;
           &lt;span class="viewmode-label"&gt;${field.label?html}:&lt;/span&gt;
           &lt;span class="viewmode-value"&gt;${field.value?html}&lt;/span&gt;
        &lt;/div&gt;
     &lt;#else&gt; 
     &lt;#-- alternative:  if form.mode == "edit" --&gt;
     &lt;#-- Create/edit form --&gt;
        &lt;label for="${fieldHtmlId}"&gt;${field.label?html}:&lt;#if field.mandatory&gt;&lt;span class="mandatory-indicator"&gt;${msg("form.required.fields.marker")}&lt;/span&gt;&lt;/#if&gt;&lt;/label&gt;
        &lt;div id="${fieldHtmlId}-AutoComplete"&gt;
     &lt;#-- Label to hold error messages from the javascript --&gt;
        &lt;p style="color:red" id="${fieldHtmlId}-scriptError"&gt;&lt;/p&gt;
          &lt;select id="${fieldHtmlId}" name="${field.name}" 
               &lt;#if field.control.params.styleClass?exists&gt;class="${field.control.params.styleClass}"&lt;/#if&gt;
               &lt;#if field.description?exists&gt;title="${field.description}"&lt;/#if&gt;
               &lt;#if field.control.params.size?exists&gt;size="${field.control.params.size}"&lt;/#if&gt; 
               &lt;#if field.disabled&gt;disabled="true"&lt;/#if&gt; &gt;
     &lt;#-- Add the field's current value if it has one as an option --&gt;
               &lt;option&gt;${field.value}&lt;/option&gt;
               &lt;/select&gt;
            &lt;div id="${fieldHtmlId}-Container"&gt;&lt;/div&gt;       
        &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>Javascript</p>
  
  <pre><code>&lt;script type="text/javascript"&gt;//&lt;![CDATA[
  (function()
  {
      &lt;#-- This references the code field from the form model. For this, the --&gt;
      &lt;#-- share config must be set to show the field for this form. --&gt;
      &lt;#if form.fields.prop_my_code??&gt;
          var code = "${form.fields.prop_my_code.value}";
      &lt;#else&gt;
          var code = 0;
      &lt;/#if&gt;
  
      // get code
      if(code === null || code === "") {
          document.getElementById('${fieldHtmlId}-scriptError').innerHTML = 'No description available.';
          return;
      }
  
      // Create webscript connection using yui connection manager
      // Note that a much more elegant way to call webscripts using Alfresco.util is 
      // available in the answers here.
      var AjaxConnectionManager = {
          handleSuccess:function(o) {
              console.log('response: '+o.responseText);
              this.processResult(o);
          }, 
  
          handleFailure:function(o) {
              var selectBox = document.getElementById('${fieldHtmlId}');
              var i;
  
              document.getElementById('${fieldHtmlId}-scriptError').innerHTML = 'Descriptions not available.';
          }, 
  
          startRequest:function() {
              console.log('webscript call to ${ds} with params code='+code);
              YAHOO.util.Connect.asyncRequest('GET', "${ds}?typecode="+code, callback, null);
          },
  
          processResult:function(o) {
              var selectBox = document.getElementById('${fieldHtmlId}');
              var jso = JSON.parse(o.responseText);
              var types = jso.types;
              console.log('adding '+types.length+' types to selectbox '+selectBox);
              var i;
  
              for(i=0;i&lt;types.length;i++) {
                  // If the current field's value is equal to this value, don't add it.
                  if(types[i] === null || types[i] === '${field.value}') {
                      continue;
                  }
                  selectBox.add(new Option(types[i], types[i]));
              }
          }
      }
  
      // Define callback methods
      var callback = {
          success:AjaxConnectionManager.handleSuccess,
          failure:AjaxConnectionManager.handleFailure,
          scope: AjaxConnectionManager
      };
  
      // Call webscript
      AjaxConnectionManager.startRequest();
  })();
  //]]&gt;&lt;/script&gt;
  &lt;#-- This closes the form.mode != "create" condition, so the js is only executed when in edit/create mode. --&gt;
  &lt;/#if&gt;
  </code></pre>