Create the detail view in an Oracle JET web app

Introduction

Oracle JavaScript Extension Toolkit (Oracle JET) components preserve the hierarchical relationship of master and detail data objects, as defined by the data source. In the viewModel for the Oracle JET web app, you can use the Oracle JET API to create a data provider object. The object represents a data array that you populate from the child data objects of a JavaScript Object Notation (JSON) document data store. The Oracle JET data provider fetches the child data objects based on the id key attribute of the current parent data object. In the view for the Oracle JET web app, the data attribute of the Oracle JET List View component binds to the data provider through a Knockout observable. The Knockout observable is also declared in the app’s viewModel source code. This code populates the observable as an instance of the detail list data provider.

Objectives

In this tutorial, you will read master-detail hierarchical data from a local JSON document and display the detail view in an Oracle JET web app. You learn how to data bind items of the child data objects to populate an Oracle JET List View component, multiple Oracle JET Input Text components, and an Oracle JET Chart component.

Prerequisites

Task 1: Data Bind the Activity Items Detail List in the View

Replace the Activity Items list bound to static data with an Oracle JET List View component bound to multiple data items of Activity Items child objects.

  1. Navigate to the JET_Web_Application/src/ts/views directory and open the dashboard.html file in an editor.

  2. Find the div element where id="container" , and then delete it and the oj-module custom element that it contains.

    <div id="activityItemsContainer" class="oj-flex-item oj-md-6 oj-sm-12">
      <div id="container">
        <oj-module config="[[moduleConfig]]"></oj-module>
      </div>
    </div>
       
    <!-- Delete the div element with id="container" so that your code is similar to the following: -->
       
    <div id="activityItemsContainer" class="oj-flex-item oj-md-6 oj-sm-12"></div>
    . . .
    
  3. Within the div element where id="activityItemsContainer", add an h3 heading element for the Activity Items detail list.

    <div id="activityItemsContainer" class="oj-flex-item oj-md-6 oj-sm-12">
      <h3 id="itemsListHeader">Activity Items</h3>
    </div>
    
  4. After the closing tag of the h3 element you created, add an oj-list-view custom HTML element to display the Activity Items detail list and a template element with a slot attribute to apply to the contents of the detail list.

    <h3 id="itemsListHeader">Activity Items</h3>
    <oj-list-view
      id="itemsList"
      class="item-display"
      data="[[itemsDataProvider]]"
      aria-labelledby="itemsListHeader"
      gridlines.item="visible"
    >
      <template slot="itemTemplate"> </template>
    </oj-list-view>
    

    The Oracle JET List View component used in an inline HTML template element with a slot attribute as a placeholder instantiates the contents of the Activity Items detail list at runtime.

  5. Within the template element you created, add three div elements with code to bind the image and name data items for each Activity Items child object.

    <template slot="itemTemplate">
      <div class="oj-flex no-wrap">
        <span
          class="demo-thumbnail oj-flex-item"
          :style.background-image="[[' url('+$current.data.image+')']]"
        ></span>
        <div class="demo-content oj-flex-item">
          <div>
            <strong>
              <oj-bind-text value="[[$current.data.name]]"></oj-bind-text>
            </strong>
          </div>
        </div>
      </div>
    </template>
    

    The $current.data.image and $current.data.name code binds the data, and an HTML template element exposes an image and activity item name for the Activity Items detail list. The $current prefix represents the current child object that the data provider for the Oracle JET List View component passes into the template.

  6. Save the dashboard.html file and leave it open in your editor.

    Your file should look similar to detail-list-task1-dashboard-html.txt.

Task 2: Create the Activity Items Child Objects in the ViewModel

Replace the oj-module inline template that you created in the previous learning path to display the Activity Items list with a JSON document call to read the Activity Items child objects from a local JSON document. In itemsDataProvider, create an instance of an Oracle JET MutableArrayDataProvider class that represents an array of child objects defined by the JSON document. Then bind the itemsArray instance to an itemsDataProvider observable. The Oracle JET List View component in the view references this observable on its data attribute to display the Activity Items detail list.

  1. Navigate to the JET_Web_Application/src/ts/viewModels directory and open the dashboard.ts file in an editor.

  2. At the top of the dashboard.ts file, after the type declaration of Activity, declare the following Item type.

    type Activity = {
       id: number;
    };
       
    type Item = {
       id: number;
       name: string;
       short_desc: string;
       price: number;
       quantity: number;
       quantity_shipped: number;
       quantity_instock: number;
       activity_id: number;
       image: string;
       value?: string;
    };
    . . .
    
  3. Delete the code from the declaration of const lg_xl_view up to but not including the declaration of this.chartTypes. The code block ends with a comment line that reads End of oj-module code. A JSON document call will replace the static data and inline template code.

    Your file should look similar to detail-list-task2a-dashboard-ts.txt.

  4. From the module imports at the top of dashboard.ts, delete the unused HtmlUtils, ResponsiveUtils, ResponsiveKnockoutUtils, and ojmodule-element import statements.

  5. Add an import statement for the ojavatar module to the import list. The ojavatar module supports the view in the next section of this tutorial.

    import * as AccUtils from "../accUtils";
    import * as ko from "knockout";
    import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider");
    import "ojs/ojselectsingle";
    import "ojs/ojlabel";
    import "ojs/ojchart";
    import * as storeData from "text!../store_data.json";
    import "ojs/ojlistview";
    import "ojs/ojavatar";
    
  6. After the this.activityDataProvider definition, within the constructor() function, add definitions for activitiesArray and itemsArray. Then declare this.itemsDataProvider as an instance of MutableArrayDataProvider. This parses the store data and makes the child objects of the first Activity parent object available in the Oracle JET List View component. In the next tutorial, you set the Activity object dynamically by using event handlers.

    . . .
    let activitiesArray = JSON.parse(storeData);
    let itemsArray = activitiesArray[0].items;
       
    this.itemsDataProvider = new MutableArrayDataProvider<Item["id"], Item>(
      itemsArray,
      { keyAttributes: "id" }
      );
       
    } // closing bracket of constructor function
    . . .
    

    Then remove the unused type annotations for large and moduleConfig, and add type annotations for itemsArray and itemsDataProvider.

    class DashboardViewModel {
        chartTypes: Array<Object>;
        chartTypesDP: MutableArrayDataProvider<ChartType["value"], ChartType>;
        chartData: Array<Object>;
        chartDataProvider: MutableArrayDataProvider<string, {}>;
        activityDataProvider: MutableArrayDataProvider<Activity["id"], Activity>;
        val: ko.Observable<string>;
        itemsArray!: Array<Object>;
        itemsDataProvider: MutableArrayDataProvider<Item["id"], Item>;
       
    

    We use the definite assignment assertion (!) for the itemsArray type annotation to communicate to TypeScript that we initialised this property in the previous step.

    Your file should look similar to detail-list-task2b-dashboard-ts.txt.

Task 3: Run the Web App

  1. In the terminal window, change to the JET_Web_Application directory and run the app.

    npx ojet serve
    

    In the Dashboard tab, the web browser displays the databound detail list with the Activity Items header.

    Activities and Activity Items list information

    Description of the illustration formatted_master_detail_list.png

  2. Leave the terminal window and the browser that displays your web app open.

Task 4: Data Bind Item Details and Pie Chart in the View

Replace the Item Details pie and bar charts with the following elements:

  1. In the dashboard.html file, within the div element where id="itemDetailsContainer", find the Item Details heading. Underneath the heading, add a horizontal rule followed by an oj-avatar custom HTML element bound to the image data item for an Activity Items child object.

    <div id="itemDetailsContainer" class="oj-flex-item oj-panel 
                                         oj-bg-neutral-30 oj-md-6 oj-sm-12">
        <h3>Item Details</h3>
        <hr class="hr-margin" />
        <oj-avatar role="img" size="lg" :aria-label="[['product image for '+ itemData().name]]" 
            :src="[[itemData().image]]"
            class="float-right">
        </oj-avatar>
    </div>
    

    The itemData observable populates the Oracle JET Avatar component by using a data provider instance that you create in the app viewModel. The itemData().image function is the Knockout observable notation for reading the current value of a data item. The data item is identified by the image property of the Activity Items child object.

  2. In dashboard.html, below the closing tag of the oj-avatar element you created, delete the oj-label for="basicSelect" custom HTML element and the oj-select-single element.

  3. Below the closing tag of the oj-avatar element you created, add four div elements with oj-bind-text custom HTML elements bound to the name, short description, price, and ID data items of an Activity Items child object.

    . . .
    </oj-avatar>
      <div id="itemName" class="data-name">
        <oj-bind-text value="[[itemData().name]]"></oj-bind-text>
      </div>
      <div id="itemDesc" class="data-desc">
        <oj-bind-text value="[[itemData().short_desc]]"></oj-bind-text>
      </div>
      <div id="itemPrice">
        <oj-bind-text value="[['Price: ' + itemData().price + ' each']]"></oj-bind-text>
      </div>
      <div id="itemId">
        <oj-bind-text value="[['Item Id: ' + itemData().id]]"></oj-bind-text>
      </div>
    . . .
    

    The itemData observables populate the Oracle JET Text Binding component by using a data provider that you create in the app viewModel. The itemData().<prop_name> function reads the current value of the named data item. The data items are identified by the name, short_desc, price, and id properties of the Activity Items child object.

  4. Below the div elements you created, delete the oj-chart id="barChart" custom HTML element.

  5. After the closing </div> tag of the div id="itemId" element, add a new div element and an oj-chart custom HTML element bound to a pie chart series for an Activity Items child object.

    . . .
    <div id="itemId">
      <oj-bind-text value="[['Item Id: ' + itemData().id]]"></oj-bind-text>
    </div>
    <div>
      <oj-chart
        type="pie"
        series="[[pieSeriesValue]]"
        animation-on-display="auto"
        animation-on-data-change="auto"
        hover-behavior="dim"
        legend.position="bottom"
        class="chartStyle"
      >
      </oj-chart>
    </div>
    . . .
    

    The pieSeriesValue observable populates the Oracle JET Pie Chart component by using a data array that you create in the app viewModel.

  6. Save the dashboard.html file.

    Your file should look similar to final-detail-list-dashboard-html.txt.

  7. Navigate to the JET_Web_Application/src/css directory and open the app.css file to add the following style definitions.

    .hr-margin {
      margin-top: 12px;
    }
       
    .data-name {
      font-size: 20px;
      font-weight: bolder;
    }
       
    .data-desc {
      font-size: 14px;
      font-weight: 400;
      font-style: italic;
      margin-bottom: 10px;
    }
       
    .float-right {
      float: right;
    }
    

    Your file should look similar to app-css-final.txt.

Task 5: Set Observables for Item Details and Pie Chart Components in the ViewModel

Get a data item from the Activity Items child object, and populate observables to data bind view components. In the view, the value attribute of the various Item Details components references the itemData observable. And the series attribute of the Pie Chart component references the pieSeriesValue observable bound to chart data from the same data item.

  1. In the dashboard.ts file, delete the code block that begins with this.val and ends with this.chartTypesDP. Also delete the unused type annotations for the removed variables. Your type annotations list and the beginning of your constructor() function should look similar to the following example.

    class DashboardViewModel {
      activityDataProvider: MutableArrayDataProvider<Activity["id"], Activity>;
      itemsArray!: Array<Object>;
      itemsDataProvider: MutableArrayDataProvider<Item["id"], Item>;
       
      constructor() {
        this.activityDataProvider = new MutableArrayDataProvider<
          Activity["id"],
          Activity
        >(JSON.parse(storeData), {
          keyAttributes: "id",
        });
    . . .
    
  2. Add the itemData and pieSeriesValue type annotations to the DashboardViewModel class.

    class DashboardViewModel {
      activityDataProvider: MutableArrayDataProvider<Activity["id"], Activity>;
      itemsArray!: Array<Object>;
      itemsDataProvider: MutableArrayDataProvider<Item["id"], Item>;
      itemData: ko.Observable<any>;
      pieSeriesValue: ko.ObservableArray;
       
      constructor() {
    . . .
    
  3. After the this.itemsDataProvider statement, set the itemData observable with a reference to the first Activity parent object and the first Activity Item child object associated with that activity in the JSON document.

      this.itemsDataProvider = new MutableArrayDataProvider<Item["id"], Item>(
        itemsArray,
        { keyAttributes: "id" }
      );
       
      this.itemData = ko.observable('');
      this.itemData(activitiesArray[0].items[0]);
       
    }   // End of constructor function
    
  4. Finally, underneath the itemData observable declaration, set the this.pieSeriesValue observable.

    this.itemData = ko.observable("");
    this.itemData(activitiesArray[0].items[0]);
       
    this.pieSeriesValue = ko.observableArray([{}]);
       
    let pieSeries = [
      { name: "Quantity in Stock", items: [this.itemData().quantity_instock] },
      { name: "Quantity Shipped", items: [this.itemData().quantity_shipped] },
    ];
    this.pieSeriesValue(pieSeries);
    

    Your file should look similar to observables-task5-dashboard-ts.txt.

Task 6: View the Master and Detail Lists

  1. Return to the browser to view the changes in your web app.

    In the Dashboard tab of your web app, the databound Oracle JET text fields, avatar, and pie chart are displayed in the Items Details container, but the lists do not respond to selections. In the next tutorial, event handlers you create will add selection functionality.

    The item details are formatted in the app

    Description of the illustration formatted_master_detail_items_list.png

  2. Close the browser window or tab that displays your running web app.

  3. In the terminal window, press Ctrl+C, and if prompted, enter y to exit the Oracle JET tooling batch job.

Next Step

To proceed to the next tutorial in this learning path, click here.

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.