The Visual Builder Cloud Service Blog

Displaying Nested Arrays with Nested Tables in Visual Builder

Shay Shmeltzer
Director of Product Management - Oracle

Hierarchical data is very common when working with databases, but showing such data can pose challenges when you want to show all the data on one page. In the past I showed how to show hierarchy using a tree component, in this blog I'm building on top of the concepts shown there to create a UI representations that shows a nested details table for each master record.

In the example we use a data set of departments and employees that belong to each one of them. We want to show a table of the employees below the details of each department. This is a common representation in "report" type of outputs.

To achieve this we are starting from the tree example, populating an ArrayTreeDataProvider with the data.

We then use an oj-bind-for-each component to dynamically render each of the master records. Binding the component to the array of master records, and using a panel with content in it bound to a specific field. You can of course expand and modify the layout of that area with additional fields and layouts.

To populate the nested tables, we are going to construct an ArrayDataProvider for each department on the fly, by passing the information about the department's employees to a JavaScript function that will construct and return an ADP. We then bind the table UI component to that JavaScript function and map fields as needed.

One tricky part is handling the order of events that are involved in displaying this page. We need to first fetch the data and construct the tree, before we are trying to iterate over the rows. We'll delay the display of the for-each section by wrapping it with an oj-bind-if that we'll set to true only after our tree is populated.

Check out the complete development flow in this video:

The end result for our page looks like this:


<div class="oj-flex">
  <div class="oj-flex-item oj-sm-12 oj-md-12">
    <oj-bind-if test="[[ $variables.ImReady ]]">
      <oj-bind-for-each data="[[ $variables.ourTree ]]">
          <div class="oj-panel oj-flex-items-pad">
            <div class="oj-flex">
              <h1 class="oj-flex-item oj-sm-12 oj-md-12">
                <oj-bind-text value="[[ $current.data.department ]]">
            <div class="oj-flex">
                class="oj-panel oj-flex-items-pad oj-flex-item oj-sm-12 oj-md-12">
                <div class="oj-flex">
                  <oj-table scroll-policy="loadMoreOnScroll"
                    class="oj-flex-item oj-sm-12 oj-md-12"
                    data="[[ $page.functions.buildADP($current.data.employeesCollection.items) ]]"


define(['ojs/ojarraytreedataprovider', 'ojs/ojarraydataprovider'], function(
  ArrayTreeDataProvider, ArrayDataProvider) {
  'use strict';

  var PageModule = function PageModule() {};

  PageModule.prototype.buildTree = function(myarray) {
    return new ArrayTreeDataProvider(myarray, {
      keyAttributes: 'id',
      keyAttributesScope: 'siblings',
      childrenAttribute: 'employeesCollection.items'

  PageModule.prototype.buildADP = function(myarray) {
    return new ArrayDataProvider(myarray, {
      keyAttributes: 'id'

  return PageModule;

Action Chain:

Action Chain Flow

Join the discussion

Comments ( 2 )
  • lem Thursday, January 7, 2021
    How do I expose the outer item(i.e. department) to become available in the inner item for example if i want to use the department as an input parameter in an event listener? OJET has oj-template-as but the event listener couldn't see the alias and throws aliasname is undefined.
  • Shay Shmeltzer Thursday, January 7, 2021
    For technical questions and how-to's I would suggest posting on our forum: https://cloudcustomerconnect.oracle.com/resources/e610f4723c/summary
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.