Nuxeo Server

How to Create a N-Level Select Widget

In this page we provide samples to have a selection widget with 3 levels by contributing a "template widget" in Studio. Each sample code below is the sample for one widget that has a different behavior (described before the code).

To create and use a new widget:

  1. Copy-paste the sample of your choice in a file that you call, for instance, "3_level_select_widget.xhtml".

    Of course you can modify the samples below to add other levels, or other behaviors. You just need to be familiar with facelets and JSF.

  2. Upload this file in the Resources > Widgets section. The widget is created. You can now use it on layouts and forms.
  3. In the layout of the document type where you want to use the widget, drag and drop the Template widget from the Advanced Widgets category on the right.
  4. Edit the properties of the widget. Here are the properties specific to custom widgets that you need to fill in.
    • Template: choose the XHTML file you have just uploaded.
    • Fields: add one field and put the XPath of the field you want to update. For instance, "dc:coverage".
    • Custom properties configuration: in our sample, you can (should) add those three properties labels and put the value you need:
      • localize
      • required
      • directoryName (should be the name of the vocabulary that holds the values that are displayed).

Widget Samples

Mono-Select 3-Level Widget

Sample example on 3 levels with widget property directoryName filled with the directory name (mono select):

<f:subview
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jstl/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:a4j="http://richfaces.org/a4j"
  xmlns:fn="http://java.sun.com/jsp/jstl/functions"
  xmlns:nxu="http://nuxeo.org/nxweb/util"
  xmlns:nxdir="http://nuxeo.org/nxdirectory"
  xmlns:nxl="http://nuxeo.org/nxforms/layout"
  xmlns:nxp="http://nuxeo.org/nxweb/pdf"
  id="#{widget.id}">
<c:if test="#{nxl:isLikeViewMode(widget.mode)}">

  <nxdir:chainSelect id="#{widget.id}_viewselect" size="3" value="#{field}"
    displayValueOnly="true" defaultRootKey="">
    <nxdir:chainSelectListbox index="0" size="0" directoryName="#{widget.properties['directoryName']}"
      localize="true" id="#{widget.id}_parent" displayObsoleteEntries="true" />
    <nxdir:chainSelectListbox index="1" size="0" directoryName="#{widget.properties['directoryName']}"
      localize="true" id="#{widget.id}_parent2" displayObsoleteEntries="true" />
    <nxdir:chainSelectListbox index="2" size="0" directoryName="#{widget.properties['directoryName']}"
      localize="true" id="#{widget.id}_child" displayObsoleteEntries="true" />
    <nxdir:chainSelectStatus display="value" id="#{widget.id}_status" />
  </nxdir:chainSelect>

</c:if>
<c:if test="#{widget.mode == 'edit'}">

  <nxdir:chainSelect size="3" value="#{field}"
    id="#{widget.id}_editselect" multiSelect="false"
    multiParentSelect="false"
    allowBranchSelection="#{widgetProperty_allowBranchSelection}"
    defaultRootKey="" required="#{widgetProperty_required}">
    <a4j:region id="#{widget.id}_region">
      <nxdir:chainSelectListbox index="0" size="1"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_parent" ordering="label">
        <f:ajax event="change"
          render="#{widget.id}_parent2 #{widget.id}_child #{widget.id}_message"
          execute="@this" />
      </nxdir:chainSelectListbox>
      <nxdir:chainSelectListbox index="1" size="1"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_parent2" ordering="label">
        <a4j:ajax event="change"
          render="#{widget.id}_child #{widget.id}_message"
          execute="@region" />
      </nxdir:chainSelectListbox>
    </a4j:region>
    <nxdir:chainSelectListbox size="1" index="2"
      directoryName="#{widget.properties['directoryName']}"
      localize="#{widget.properties['localize']}"
      id="#{widget.id}_child" ordering="label" />
  </nxdir:chainSelect>
  <h:message styleClass="errorMessage" for="#{widget.id}_editselect"
    id="#{widget.id}_message" />

</c:if>
</f:subview>

Multi-Select 3-Level Widget

Sample example on 3 levels with widget property directoryName filled with the directory name (multi select):

<f:subview
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jstl/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:a4j="http://richfaces.org/a4j"
  xmlns:fn="http://java.sun.com/jsp/jstl/functions"
  xmlns:nxu="http://nuxeo.org/nxweb/util"
  xmlns:nxdir="http://nuxeo.org/nxdirectory"
  xmlns:nxl="http://nuxeo.org/nxforms/layout"
  xmlns:nxp="http://nuxeo.org/nxweb/pdf"
  id="#{widget.id}">
<c:if test="#{nxl:isLikeViewMode(widget.mode)}">

  <nxdir:chainSelect id="#{widget.id}_viewselect" size="3"
    value="#{field}" displayValueOnly="true" multiSelect="true"
    defaultRootKey="">
    <nxdir:chainSelectListbox index="0" size="4"
    directoryName="#{widget.properties['directoryName']}"
    localize="#{widget.properties['localize']}"
    id="#{widget.id}_parent" />
    <nxdir:chainSelectListbox size="4"
      directoryName="#{widget.properties['directoryName']}" index="1"
      localize="#{widget.properties['localize']}"
      id="#{widget.id}_parent2" />
    <nxdir:chainSelectListbox size="4"
      directoryName="#{widget.properties['directoryName']}" index="2"
      localize="#{widget.properties['localize']}"
      id="#{widget.id}_child" />
    <nxdir:chainSelectStatus display="value" id="#{widget.id}_status" />
  </nxdir:chainSelect>

</c:if>
<c:if test="#{widget.mode == 'edit'}">

  <a4j:region id="#{widget.id}_region" renderRegionOnly="true">
    <nxdir:chainSelect size="3" value="#{field}"
      id="#{widget.id}_editselect" multiSelect="true"
      multiParentSelect="true"
      allowBranchSelection="#{widgetProperty_allowBranchSelection}"
      defaultRootKey="" required="#{widgetProperty_required}">
      <nxdir:chainSelectListbox index="0" size="4"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_parent" ordering="label">
        <a4j:ajax event="change"
          render="#{widget.id}_parent2 #{widget.id}_child #{widget.id}_message"
          execute="@this" />
      </nxdir:chainSelectListbox>
      <nxdir:chainSelectListbox index="1" size="4"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_parent2" ordering="label">
        <a4j:ajax event="change"
          render="#{widget.id}_child #{widget.id}_message"
          immediate="true" />
      </nxdir:chainSelectListbox>
      <nxdir:chainSelectListbox size="4" index="2"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_child" ordering="label" />
      <a4j:commandButton value="#{messages['command.add']}"
        styleClass="button" immediate="true"
        actionListener="#{chainSelectActions.add}"
        render="#{widget.id}_status #{widget.id}_message"
        id="#{widget.id}_add" />
      <br />
      <nxdir:chainSelectStatus display="value"
        entryCssStyle="background-color: #DDEEFF"
        label="#{messages['label.chainSelect.selection']}"
        id="#{widget.id}_status">
        <f:facet name="removeButton">
          <a4j:commandButton
            actionListener="#{chainSelectActions.delete}"
            execute="@this" render="#{widget.id}_status"
            image="/icons/toggle_minus.png"
            id="#{widget.id}_delete" />
        </f:facet>
      </nxdir:chainSelectStatus>
    </nxdir:chainSelect>
  </a4j:region>
  <h:message styleClass="errorMessage" for="#{widget.id}_editselect"
    id="#{widget.id}_message" />

</c:if>
</f:subview>

Complete Examples with CSV (Plain) and PDF Rendering

Mono-Select Widget

<f:subview
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jstl/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:a4j="http://richfaces.org/a4j"
  xmlns:fn="http://java.sun.com/jsp/jstl/functions"
  xmlns:nxu="http://nuxeo.org/nxweb/util"
  xmlns:nxdir="http://nuxeo.org/nxdirectory"
  xmlns:nxl="http://nuxeo.org/nxforms/layout"
  xmlns:nxp="http://nuxeo.org/nxweb/pdf"
  id="#{widget.id}">
<c:if test="#{nxl:isLikePlainMode(widget.mode)}">
<f:subview rendered="#{not empty field}"><nxdir:directoryEntryOutput
  directoryName="#{widget.properties['directoryName']}"
    value="#{fn:split(field, '/')[0]}"
    localize="#{widget.properties['localize']}" />/<nxdir:directoryEntryOutput
    directoryName="#{widget.properties['directoryName']}"
    value="#{fn:split(field, '/')[1]}"
    localize="#{widget.properties['localize']}" />/<nxdir:directoryEntryOutput
    directoryName="#{widget.properties['directoryName']}"
    value="#{field}"
    localize="#{widget.properties['localize']}"
    keySeparator="/" />
</f:subview>
</c:if>
<c:if test="#{widget.mode == 'pdf'}">
  <nxp:html>
   <nxdir:chainSelect id="#{widget.id}_viewselect" size="3" value="#{field}"
    displayValueOnly="true" defaultRootKey="">
     <nxdir:chainSelectListbox index="0" size="0" directoryName="#{widget.properties['directoryName']}"
       localize="true" id="#{widget.id}_parent" displayObsoleteEntries="true" />
     <nxdir:chainSelectListbox index="1" size="0" directoryName="#{widget.properties['directoryName']}"
       localize="true" id="#{widget.id}_parent2" displayObsoleteEntries="true" />
     <nxdir:chainSelectListbox index="2" size="0" directoryName="#{widget.properties['directoryName']}"
       localize="true" id="#{widget.id}_child" displayObsoleteEntries="true" />
     <nxdir:chainSelectStatus display="value" id="#{widget.id}_status" />
   </nxdir:chainSelect>
  </nxp:html>
</c:if>
<c:if test="#{nxl:isLikeViewMode(widget.mode)}">

  <nxdir:chainSelect id="#{widget.id}_viewselect" size="3" value="#{field}"
    displayValueOnly="true" defaultRootKey="">
    <nxdir:chainSelectListbox index="0" size="0" directoryName="#{widget.properties['directoryName']}"
      localize="true" id="#{widget.id}_parent" displayObsoleteEntries="true" />
    <nxdir:chainSelectListbox index="1" size="0" directoryName="#{widget.properties['directoryName']}"
      localize="true" id="#{widget.id}_parent2" displayObsoleteEntries="true" />
    <nxdir:chainSelectListbox index="2" size="0" directoryName="#{widget.properties['directoryName']}"
      localize="true" id="#{widget.id}_child" displayObsoleteEntries="true" />
    <nxdir:chainSelectStatus display="value" id="#{widget.id}_status" />
  </nxdir:chainSelect>

</c:if>
<c:if test="#{widget.mode == 'edit'}">

  <nxdir:chainSelect size="3" value="#{field}"
    id="#{widget.id}_editselect" multiSelect="false"
    multiParentSelect="false"
    allowBranchSelection="#{widgetProperty_allowBranchSelection}"
    defaultRootKey="" required="#{widgetProperty_required}">
    <a4j:region id="#{widget.id}_region">
      <nxdir:chainSelectListbox index="0" size="1"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_parent" ordering="label">
        <f:ajax event="change"
          render="#{widget.id}_parent2 #{widget.id}_child #{widget.id}_message"
          execute="@this" />
      </nxdir:chainSelectListbox>
      <nxdir:chainSelectListbox index="1" size="1"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_parent2" ordering="label">
        <a4j:ajax event="change"
          render="#{widget.id}_child #{widget.id}_message"
          execute="@region" />
      </nxdir:chainSelectListbox>
    </a4j:region>
    <nxdir:chainSelectListbox size="1" index="2"
      directoryName="#{widget.properties['directoryName']}"
      localize="#{widget.properties['localize']}"
      id="#{widget.id}_child" ordering="label" />
  </nxdir:chainSelect>
  <h:message styleClass="errorMessage" for="#{widget.id}_editselect"
    id="#{widget.id}_message" />

</c:if>
</f:subview>

Multi-Select Widget

<f:subview
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jstl/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:a4j="http://richfaces.org/a4j"
  xmlns:fn="http://java.sun.com/jsp/jstl/functions"
  xmlns:nxu="http://nuxeo.org/nxweb/util"
  xmlns:nxdir="http://nuxeo.org/nxdirectory"
  xmlns:nxl="http://nuxeo.org/nxforms/layout"
  xmlns:nxp="http://nuxeo.org/nxweb/pdf"
  id="#{widget.id}">
<c:if test="#{nxl:isLikePlainMode(widget.mode)}"><nxu:inputList
  value="#{field}" model="chainModel"><nxdir:directoryEntryOutput
  directoryName="#{widget.properties['directoryName']}"
    value="#{fn:split(chainModel.rowData, '/')[0]}"
    localize="#{widget.properties['localize']}" />/<nxdir:directoryEntryOutput
    directoryName="#{widget.properties['directoryName']}"
    value="#{fn:split(chainModel.rowData, '/')[1]}"
    localize="#{widget.properties['localize']}" />/<nxdir:directoryEntryOutput
    directoryName="#{widget.properties['directoryName']}"
    value="#{chainModel.rowData}"
    localize="#{widget.properties['localize']}"
    keySeparator="/" /><h:outputText
  rendered="#{chainModel.rowIndex != chainModel.rowCount -1}" value=", " /></nxu:inputList>
</c:if>
<c:if test="#{widget.mode == 'pdf'}">
  <nxp:html>
    <nxdir:chainSelect id="#{widget.id}_viewselect" size="3"
      value="#{field}" displayValueOnly="true" multiSelect="true"
      defaultRootKey="">
      <nxdir:chainSelectListbox index="0" size="4"
      directoryName="#{widget.properties['directoryName']}"
      localize="#{widget.properties['localize']}"
      id="#{widget.id}_parent" />
      <nxdir:chainSelectListbox size="4"
        directoryName="#{widget.properties['directoryName']}" index="1"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_parent2" />
      <nxdir:chainSelectListbox size="4"
        directoryName="#{widget.properties['directoryName']}" index="2"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_child" />
      <nxdir:chainSelectStatus display="value" id="#{widget.id}_status" />
    </nxdir:chainSelect>
    </nxp:html>
</c:if>
<c:if test="#{nxl:isLikeViewMode(widget.mode)}">

  <nxdir:chainSelect id="#{widget.id}_viewselect" size="3"
    value="#{field}" displayValueOnly="true" multiSelect="true"
    defaultRootKey="">
    <nxdir:chainSelectListbox index="0" size="4"
    directoryName="#{widget.properties['directoryName']}"
    localize="#{widget.properties['localize']}"
    id="#{widget.id}_parent" />
    <nxdir:chainSelectListbox size="4"
      directoryName="#{widget.properties['directoryName']}" index="1"
      localize="#{widget.properties['localize']}"
      id="#{widget.id}_parent2" />
    <nxdir:chainSelectListbox size="4"
      directoryName="#{widget.properties['directoryName']}" index="2"
      localize="#{widget.properties['localize']}"
      id="#{widget.id}_child" />
    <nxdir:chainSelectStatus display="value" id="#{widget.id}_status" />
  </nxdir:chainSelect>

</c:if>
<c:if test="#{widget.mode == 'edit'}">

  <a4j:region id="#{widget.id}_region" renderRegionOnly="true">
    <nxdir:chainSelect size="3" value="#{field}"
      id="#{widget.id}_editselect" multiSelect="true"
      multiParentSelect="true"
      allowBranchSelection="#{widgetProperty_allowBranchSelection}"
      defaultRootKey="" required="#{widgetProperty_required}">
      <nxdir:chainSelectListbox index="0" size="4"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_parent" ordering="label">
        <a4j:ajax event="change"
          render="#{widget.id}_parent2 #{widget.id}_child #{widget.id}_message"
          execute="@this" />
      </nxdir:chainSelectListbox>
      <nxdir:chainSelectListbox index="1" size="4"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_parent2" ordering="label">
        <a4j:ajax event="change"
          render="#{widget.id}_child #{widget.id}_message"
          immediate="true" />
      </nxdir:chainSelectListbox>
      <nxdir:chainSelectListbox size="4" index="2"
        directoryName="#{widget.properties['directoryName']}"
        localize="#{widget.properties['localize']}"
        id="#{widget.id}_child" ordering="label" />
      <a4j:commandButton value="#{messages['command.add']}"
        styleClass="button" immediate="true"
        actionListener="#{chainSelectActions.add}"
        render="#{widget.id}_status #{widget.id}_message"
        id="#{widget.id}_add" />
      <br />
      <nxdir:chainSelectStatus display="value"
        entryCssStyle="backgroundcolor: #DDEEFF"
        label="#{messages['label.chainSelect.selection']}"
        id="#{widget.id}_status">
        <f:facet name="removeButton">
          <a4j:commandButton
            actionListener="#{chainSelectActions.delete}"
            execute="@this" render="#{widget.id}_status"
            image="/icons/toggle_minus.png"
            id="#{widget.id}_delete" />
        </f:facet>
      </nxdir:chainSelectStatus>
    </nxdir:chainSelect>
  </a4j:region>
  <h:message styleClass="errorMessage" for="#{widget.id}_editselect"
    id="#{widget.id}_message" />

</c:if>
</f:subview>
7 days ago manonlumeau Remove updated review date
3 years ago Anahide Tchertchian 26
3 years ago Anahide Tchertchian 25 | NXP-16605: templates update again (wrong version edited before...)
3 years ago Anahide Tchertchian 24 | NXP-16605: another template update for incmplete selection related bugs
3 years ago Anahide Tchertchian 23 | fix the "onchange" event to "change" (again...)
3 years ago Anahide Tchertchian 22 | fix the "onchange" event to "change"
3 years ago Anahide Tchertchian 21 | fix the "onchange" event to "change"
3 years ago Anahide Tchertchian 20 | NXP-16605: update templates to fix "Incomplete selections are not allowed" validation message issue
3 years ago Solen Guitter 19
3 years ago Anahide Tchertchian 18
3 years ago Anahide Tchertchian 17 | NXDOC-414: update samples for JSF2 migration
4 years ago Manon Lumeau 16
4 years ago Manon Lumeau 15
4 years ago Solen Guitter 14 | Remove 5.4 reference
4 years ago Solen Guitter 13
5 years ago Solen Guitter 12
6 years ago Anahide Tchertchian 10 | fix size value on multiselect example
6 years ago Anahide Tchertchian 11 | Migrated to Confluence 4.0
6 years ago Laurent Doguin 9
6 years ago Laurent Doguin 8 | add template widget configuration screenshot
7 years ago Solen Guitter 7
7 years ago Alain Escaffre 6
7 years ago Alain Escaffre 5
7 years ago Anahide Tchertchian 4
7 years ago Anahide Tchertchian 3
7 years ago Anahide Tchertchian 2
7 years ago Alain Escaffre 1
History: Created by Alain Escaffre

We'd love to hear your thoughts!

All fields required