Today we have a question from Laurent Cathala, who asks how to have virtual navigation with more than two levels.

I actually thought it was quite complicated, that you had to create a custom Seam component to handle a custom XHTML widget. But in fact, you can do it all within Nuxeo Studio.

Three Level Hierarchical vocabularyThree Level Hierarchical vocabulary

First step: Create a 3-level hierarchical vocabulary

This is the part I thought was not do-able in Studio - creating a vocabulary with more than 2 levels. It’s actually quite easy, thanks to the ‘Set tree depth’ button - as you can see on this screenshot. I’ve chosen 3 and added a simple 3-level entry.

Second Step: Update the custom widget

You need a custom widget to be able to choose/view an entry in our 3-level vocabulary. You can find the code in our documentation, or right here for a three-level mono selection:

<f:subview
  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="https://ajax4jsf.dev.java.net/ajax"
  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"
  id="#{widget.id}"
>
  <c:if test="#{widget.mode != 'edit' and not empty field_0}">
    <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'}">
    <a4j:region id="#{widget.id}_region" renderRegionOnly="true">
      <nxdir:chainSelect
        size="3"
        value="#{field}"
        id="#{widget.id}_editselect"
        multiSelect="false"
        multiParentSelect="false"
        allowBranchSelection="false"
        defaultRootKey=""
        required="#{widget.required}"
      >
        <nxdir:chainSelectListbox
          index="0"
          size="1"
          directoryName="#{widget.properties['directoryName']}"
          localize="#{widget.properties['localize']}"
          id="#{widget.id}_parent"
          ordering="label"
        >
          <a4j:support
            event="onchange"
            reRender="#{widget.id}_parent2,#{widget.id}_child,#{widget.id}_message"
            immediate="true"
          />
        </nxdir:chainSelectListbox>
        <nxdir:chainSelectListbox
          index="1"
          size="1"
          directoryName="#{widget.properties['directoryName']}"
          localize="#{widget.properties['localize']}"
          id="#{widget.id}_parent2"
          ordering="label"
        >
          <a4j:support
            event="onchange"
            reRender="#{widget.id}_child,#{widget.id}_message"
            immediate="true"
          />
        </nxdir:chainSelectListbox>
        <nxdir:chainSelectListbox
          size="1"
          index="2"
          directoryName="#{widget.properties['directoryName']}"
          localize="#{widget.properties['localize']}"
          id="#{widget.id}_child"
          ordering="label"
        />
      </nxdir:chainSelect>
    </a4j:region>
    <a4j:outputPanel ajaxRendered="true">
      <h:message
        styleClass="errorMessage"
        for="#{widget.id}_editselect"
        id="#{widget.id}_message"
      />
    </a4j:outputPanel>
  </c:if>
</f:subview>

Configure a Template WidgetConfigure a Template Widget

Third Step: Update the layout

We must use our new template widget. You can do so when choosing Template in the Advanced Widgets. You have at least three things to configure in the widget. Select the right widget_template, enter the document field to map to this widget (for instance dublincore:nature) and do not forget to add the widget property ‘directoryName’. Its value should be the ID of your previously defined 3-level hierarchical vocabulary.

Three level Virtual Navigation3-level Virtual Navigation

Fourth Step: Set up the virtual navigation

Now that we have our vocabulary and we can use it in our document layout, let’s set up the virtual navigation. You need to select the same document field that you used in your widget, choose the right vocabulary and add two others with the same vocabulary. Take a look at the screenshot.

And you’re all set. You just configured a 3-level virtual navigation using only Nuxeo Studio. And if you still find this cumbersome, know that this will probably be made fully automatic in one of the next versions of Studio.