title: Dynamically bind an Edit Box in a custom control to a managed bean
body: <p>I've read a number of excellent posts and articles about dynamically binding fields in a custom control, but they have all assumed a document data source.</p>
  
  <p>I want to allow the possibility of a managed bean data source. I tried setting the property type to <code>com.ibm.xsp.model.DataSource</code> or <code>com.ibm.xsp.extlib.model.ObjectDataSource</code> and neither of those work with the following xml:</p>
  
  <pre><code>&lt;xp:inputText
      id="input"
      value="${compositeData.dsn[compositeData.fieldName]}"
  &gt;
  &lt;/xp:inputText&gt;
  </code></pre>
  
  <p>Where the control is used I have passed in custom data like so:</p>
  
  <pre><code>&lt;xc:input
      dsn="#{issue}"
      fieldName="Database"
  &gt;
  &lt;/xc:input&gt;
  </code></pre>
  
  <p>For my test purpose, I have a managed bean named <code>issue</code> and I called my field <code>Database</code>. I would normally bind to <code>#{issue.Database}</code> but I can't figure out how to do that dynamically. Ideally, I would like to support document data sources as well, but if I can't do both then I need to bind to the managed bean.</p>
  
  <p>Edit: The problem seems to be the array-notation. If I hardcode my value to <code>#{issue.Database}</code> it works but if I hardcode it to <code>#{issue[Database]}</code> it fails. So the question is if there is an alternative representation of dot-notation. I don't have time today, but I wonder if instead of separating dsn and fieldName if I just passed #{issue} into dsn and used that as my data binding would that work? I will try that when I get a chance.</p>
  
  <p>Edit2: As it appears the problem may be related to the bean I'm using, I'll post the code for that here.</p>
  
  <p><strong>AbstractMapModel</strong></p>
  
  <pre><code>public abstract class AbstractMapModel implements Serializable, DataObject {
      private static final long serialVersionUID = 1L;
      private Map&lt;Object, Object&gt; values;
  
      public Class&lt;?&gt; getType(final Object key) {
          Class&lt;?&gt; result = null;
          if (getValues().containsKey(key)) {
              Object value = getValues().get(key);
              if (value != null) {
                  result = value.getClass();
              }
          }
          return result;
      }
  
      protected Map&lt;Object, Object&gt; getValues() {
          if (values == null) {
              values = new HashMap&lt;Object, Object&gt;();
          }
          return values;
      }
  
      public Object getValue(final Object key) {
          return getValues().get(key);
      }
  
      public boolean isReadOnly(final Object key) {
          return false;
      }
  
      public void setValue(final Object key, final Object value) {
          getValues().put(key, value);
      }
  }
  </code></pre>
  
  <p><strong>AbstractDocumentMapModel</strong></p>
  
  <pre><code>public abstract class AbstractDocumentMapModel extends AbstractMapModel {
  private static final long serialVersionUID = 1L;
  private String unid;
  
  public AbstractDocumentMapModel() {
      String documentId = ExtLibUtil.readParameter(FacesContext
              .getCurrentInstance(), "id");
      if (StringUtil.isNotEmpty(documentId)) {
          load(documentId);
      }
  }
  
  protected abstract String getFormName();
  
  public String getUnid() {
      return unid;
  }
  
  public void setUnid(String unid) {
      this.unid = unid;
  }
  
  public void load(final String unid) {
      setUnid(unid);
      Document doc = null;
      try {
          if (StringUtil.isNotEmpty(getUnid())) {
              doc = ExtLibUtil.getCurrentDatabase().getDocumentByUNID(
                      getUnid());
              DominoDocument wrappedDoc = DominoDocument.wrap(doc
                      .getParentDatabase().getFilePath(), // databaseName
                      doc, // Document
                      null, // computeWithForm
                      null, // concurrencyMode
                      false, // allowDeleteDocs
                      null, // saveLinksAs
                      null // webQuerySaveAgent
                      );
              for (Object eachItem : doc.getItems()) {
                  if (eachItem instanceof Item) {
                      Item item = (Item) eachItem;
                      String itemName = item.getName();
                      if (!("$UpdatedBy".equalsIgnoreCase(itemName) || "$Revisions"
                              .equalsIgnoreCase(itemName))) {
                          setValue(item.getName(), wrappedDoc.getValue(item
                                  .getName()));
                      }
                      DominoUtil.incinerate(eachItem);
                  }
              }
          }
      } catch (Throwable t) {
          t.printStackTrace();
      } finally {
          DominoUtil.incinerate(doc);
      }
  }
  
  protected boolean postSave() {
      return true;
  }
  
  protected boolean querySave() {
      return true;
  }
  
  public boolean save() {
      boolean result = false;
      if (querySave()) {
          Document doc = null;
          try {
              if (StringUtil.isEmpty(getUnid())) {
                  doc = ExtLibUtil.getCurrentDatabase().createDocument();
                  setUnid(doc.getUniversalID());
                  doc.replaceItemValue("Form", getFormName());
              } else {
                  doc = ExtLibUtil.getCurrentDatabase().getDocumentByUNID(
                          getUnid());
              }
              for (Entry&lt;Object, Object&gt; entry : getValues().entrySet()) {
                  String itemName = entry.getKey().toString();
                  doc.replaceItemValue(itemName, DominoUtil
                          .toDominoFriendly(entry.getValue()));
              }
              if (doc.save()) {
                  result = postSave();
              }
          } catch (Throwable t) {
              t.printStackTrace();
          } finally {
              DominoUtil.incinerate(doc);
          }
      }
      return result;
  }
  </code></pre>
  
  <p>}</p>
  
  <p><strong>IssueModel</strong></p>
  
  <pre><code>public class IssueModel extends AbstractDocumentMapModel implements
      Serializable {
  private static final long serialVersionUID = 1L;
  
  @Override
  protected String getFormName() {
      return "frmIssue";
  }
  
  @Override
  protected boolean querySave() {
      return super.querySave();
  }
  
  @Override
  public boolean isReadOnly(final Object key) {
      boolean result = super.isReadOnly(key);
      /**
       * Implement read only logic here as follows
       * 
       * if ("jobTitle".equalsIgnoreCase((String) key)) { if
       * (!ExtLibUtil.getXspContext().getUser().getRoles().contains("[HR]")) {
       * result = true; } }
       */
      return result;
  }
  </code></pre>
  
  <p>}</p>
  
  <p><strong>ccFieldset</strong></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;xp:view
      xmlns:xp="http://www.ibm.com/xsp/core"
  &gt;
      &lt;div
          class="form-group"
      &gt;
          &lt;xp:label
              id="label"
              for="input"
              value="${compositeData.label.text}"
          &gt;
              &lt;xp:this.styleClass&gt;&lt;![CDATA[${javascript:styleClass = "control-label col-" + compositeData.sz + "-" + compositeData.label.columns;
  return styleClass;}]]&gt;&lt;/xp:this.styleClass&gt;
          &lt;/xp:label&gt;
          &lt;xp:div&gt;
              &lt;xp:this.styleClass&gt;&lt;![CDATA[${javascript:styleClass = "col-" + compositeData.sz + "-" + compositeData.input.columns;
  return styleClass;}]]&gt;&lt;/xp:this.styleClass&gt;
              &lt;xp:inputText
                  id="input"
              &gt;
                  &lt;xp:this.value&gt;&lt;![CDATA[${javascript:"#{"+compositeData.BindTo+"}"}]]&gt;&lt;/xp:this.value&gt;
                  &lt;xp:this.styleClass&gt;&lt;![CDATA[${javascript:styleClass = "input-" + compositeData.sz;
  return styleClass;}]]&gt;&lt;/xp:this.styleClass&gt;
              &lt;/xp:inputText&gt;
          &lt;/xp:div&gt;
      &lt;/div&gt;
  &lt;/xp:view&gt;
  </code></pre>
  
  <p><strong>Working field in xpage</strong></p>
  
  <pre><code>            &lt;div
              class="form-group"
          &gt;
              &lt;xp:label
                  value="Database"
                  id="database_Label1"
                  for="database1"
                  styleClass="col-sm-2 control-label"
              &gt;
              &lt;/xp:label&gt;
              &lt;div
                  class="col-sm-6"
              &gt;
                  &lt;xp:inputText
                      value="#{issue.Database}"
                      id="database1"
                      styleClass="input-sm"
                  &gt;
                  &lt;/xp:inputText&gt;
              &lt;/div&gt;
          &lt;/div&gt;
  </code></pre>
  
  <p><strong>Not working ccFieldset in xpage</strong></p>
  
  <pre><code>            &lt;xc:fieldset sz="md"&gt;
                  &lt;xc:this.input&gt;
                      &lt;xc:input
                          columns="10"
                          bindTo="issue.Database"
                      &gt;
                      &lt;/xc:input&gt;
                  &lt;/xc:this.input&gt;
                  &lt;xc:this.label&gt;
                      &lt;xc:label
                          columns="2"
                          text="test"
                      &gt;
                      &lt;/xc:label&gt;
                  &lt;/xc:this.label&gt;
              &lt;/xc:fieldset&gt;
  </code></pre>