Create the detail view in an Oracle JET virtual DOM 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 previous tutorial, you created a data provider object using an instance of the MutableArrayDataProvider
class. Using props
, you passed the data provider object to the List View component in the ActivityContainer
component and rendered the data items. Now, using the same JSON data store, you will create the detail view of your app by populating the ActivityItemContainer
and ItemDetailContainer
components, respectively, with the activity items of a given activity and the specific item details of an activity item by passing them data from a parent container using props
.
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 virtual DOM app. You will data bind multiple items of the child data objects from a local JSON document and populate the rows of an Oracle JET List View component in the ActivityItemContainer
component with that data, as well as Oracle JET Avatar and Chart components in the ItemDetailContainer
component.
Prerequisites
- A development environment set up to create Oracle JET virtual DOM apps that includes an installation of Node.js
- Completion of the previous tutorial in this learning path, Create the Master View in an Oracle JET Virtual DOM App
Task 1: Create a Data Provider in Parent Container 2
-
Navigate to the
JET-Virtual-DOM-app/src/components
directory and open theParentContainer2.tsx
file in an editor. -
At the top of the file, add
import
statements for theMutableArrayDataProvider
class and the JSON data in thestore_data.json
file.import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider"); import * as storeData from "text!./store_data.json";
-
Create
Item
andActivityItem
type aliases.type Item = { id: number; name: string; short_desc?: string; price?: number; quantity?: number; quantity_shipped?: number; quantity_instock?: number; activity_id?: number; image?: string; }; type ActivityItem = { id: number; name: string; items: Array<Item>; short_desc: string; image: string; };
-
Add an
activityItemDP
instance of aMutableArrayDataProvider
, as well as two variables used to provide the data provider with the Baseball activity’s items from the JSON data source.const activityData = JSON.parse(storeData); let activityItemsArray = activityData[0].items // Create data provider instance for the array of activity items for the Baseball activity const activityItemDP = new MutableArrayDataProvider<ActivityItem["id"], ActivityItem>(activityItemsArray, { keyAttributes: "id", });
-
In the
ParentContainer2
function, add adata
attribute to theActivityItemContainer
element to pass the data provider object to theActivityItemContainer
component usingprops
.<ActivityItemContainer data={activityItemDP} />
Save the file. Your code should look similar to
parent-container2-1-tsx.txt
.
Task 2: Create the Activity Item Container’s List View Component
-
Navigate to the
JET-Virtual-DOM-app/src/components/ActivityItem
directory and open theActivityItemContainer.tsx
file in an editor. -
At the top of the file, delete the
import
statements for theResponsiveUtils
module and theuseRef
,useState
, anduseEffect
hooks. Also delete thesm_md_view
variable. -
Inside the
ActivityItemContainer
function, remove code that makes use of hooks and state and that enables the conditional display of content in thereturn
statement. Your function should look similar to the following code.const ActivityItemContainer = () => { return ( <div id="activityItemsContainer" class="oj-flex-item oj-bg-success-20 oj-sm-padding-4x-start oj-md-6 oj-sm-12"> <div id="container" class="item-display no-wrap"> <h3>Activity Items</h3> <ul> <li class="li-item">Louisville Slugger Bat</li> . . . </ul> </div> </div> ); };
-
Delete the
ul
element from thereturn
statement, and in thediv
element whereid="container"
, remove theclass
attribute. TheActivityItemContainer
function should look similar to the following code.const ActivityItemContainer = () => { return ( <div id="activityItemsContainer" class="oj-flex-item oj-bg-success-20 oj-sm-padding-4x-start oj-md-6 oj-sm-12"> <div id="container"> <h3>Activity Items</h3> </div> </div> ); };
-
Add the following
import
statements for the Oracle JET List View component andMutableArrayDataProvider
class to the top of the file.import "ojs/ojlistview"; import { ojListView } from "ojs/ojlistview"; import MutableArrayDataProvider = require("ojs/ojmutablearraydataprovider");
-
Add
Props
,ActivityItem
, andItem
type aliases below the block ofimport
statements.type Props = { data?: MutableArrayDataProvider<ActivityItem["id"], ActivityItem>; value?: string; }; type Item = { id: number; name: string; short_desc?: string; price?: number; quantity?: number; quantity_shipped?: number; quantity_instock?: number; activity_id?: number; image?: string; }; type ActivityItem = { id: number; name: string; items: Array<Item>; short_desc: string; image: string; };
-
Create the
listItemRenderer
function that renders each list item and includesspan
anddiv
elements to populate the List View component’s rows with a background image, name, and short description.const listItemRenderer = (item: ojListView.ItemTemplateContext) => { const image = item.data.image.replace("css", "styles"); return ( <div class="oj-flex no-wrap"> <span class="demo-thumbnail oj-flex-item" style={"background-image:url(" + image + ")"}></span> <div class="demo-content oj-flex-item"> <div> <strong>{item.data.name}</strong> </div> <span class="demo-metadata">{item.data.short_desc}</span> </div> </div> ); };
-
Underneath the
listItemRenderer
function, add aListViewProps
type alias and two variables to define the gridline and scroll properties for the List View component.type ListViewProps = ComponentProps<"oj-list-view">; const gridlinesItemVisible: ListViewProps["gridlines"] = { item: "visible" }; const scrollPolicyOpts: ListViewProps["scrollPolicyOptions"] = { fetchSize: 5 };
-
Add
props
to theActivityItemContainer
function definition.const ActivityItemContainer = (props: Props) => {
-
Inside the
ActivityItemContainer
function’sreturn
statement, add an Oracle JET List View component, where the data provider object that is passed down fromParentContainer2
is accessed viaprops
in the List View’sdata
attribute.return ( <div id="activityItemsContainer" class="oj-flex-item oj-bg-success-20 oj-sm-padding-4x-start oj-md-6 oj-sm-12"> <div id="container"> <h3>Activity Items</h3> <oj-list-view id="itemsList" class="item-display" aria-labelledby="activitiesHeader" data={props.data} gridlines={gridlinesItemVisible} selectionMode="single" scrollPolicy="loadMoreOnScroll" scrollPolicyOptions={scrollPolicyOpts}> </oj-list-view> </div> </div> );
-
Within the List View component, add a
template
element with aslot
attribute to render each item in the list.. . . <template slot="itemTemplate" render={listItemRenderer}></template> </oj-list-view>
Save the file. Your code should look similar to
activity-item-container-1-tsx.txt
.
Task 3: Run the Virtual DOM App
-
In the terminal window, navigate to the
JET_Virtual_DOM_app
directory and run the app.npx ojet serve
The app runs in the web browser, and the Activity Items list displays the Baseball activity items with their short descriptions and thumbnail images.
Description of the illustration activity_items_displayed.png
-
Leave the terminal window and the browser that displays your app open.
Task 4: Create the Item Detail Chart and Avatar Components
Pass the item details of the SureCatch Baseball Glove activity item from the ParentContainer2
component to the ItemDetailContainer
component via props
, binding the data to the Oracle JET Chart and Avatar components, as well as to multiple text fields.
-
Navigate to the
JET-Virtual-DOM-app/src/components
directory and open theParentContainer2.tsx
file in an editor. -
Below the
activityItemDP
instance, add aspecificItem
variable to hold the item details data for the SureCatch Baseball Glove activity item.// Create an object variable holding the item details for the SureCatch Baseball Glove const specificItem: Item = activityData[0].items[0]
-
Add an
item
attribute to theItemDetailContainer
element to pass down the item details to the child component viaprops
.<ItemDetailContainer item={specificItem} />
Save the file. Your code should look similar to
parent-container2-2-tsx.txt
. -
Navigate to the
JET-Virtual-DOM-app/src/components/ItemDetailContainer
directory and openItemDetailContainer.tsx
in an editor. -
Remove these
import
statements from the top of the file.import { useState, useCallback } from "preact/hooks"; import "ojs/ojlabel"; import "ojs/ojselectsingle"; import { ojSelectSingle } from "ojs/ojselectsingle"; import * as storeData from "text!../store_data.json"; import "ojs/ojlistview"; import { ojListView } from "ojs/ojlistview"; import "ojs/ojlistitemlayout";
-
Add an
import
statement for theojavatar
module.import "ojs/ojavatar";
-
Remove the
ChartType
,ListViewProps
, andActivity
type aliases; thechartTypeData
,gridlinesItemVisible
, andchartData
variables; and theactivityDataProvider
,chartTypesDP
andchartDataProvider
data provider instances. -
Add
Props
andItem
type aliases.type Props = { item?: Item | null; }; type Item = { id: number; name: string; short_desc?: string; price?: number; quantity?: number; quantity_shipped?: number; quantity_instock?: number; activity_id?: number; image?: string; };
-
Inside the
ItemDetailContainer
function, delete the following lines of code.const [val, setVal] = useState("bar" as ChartProps['type']); const valChangeHandler = useCallback( (event: ojSelectSingle.valueChanged<ChartType['value'], ChartType>) => { setVal(event.detail.value as ChartProps['type']); }, [val, setVal] );
-
Replace the
chartItem
template variable.const chartItem = ( item: ojChart.ItemTemplateContext<ChartItem["id"], ChartItem> ) => { return ( <oj-chart-item value={item.data.value} groupId={[0]} seriesId={item.data.series} ></oj-chart-item> ); };
-
Add
props
to theItemDetailContainer
function definitionconst ItemDetailContainer = (props: Props) => {
-
Add a
pieDataProvider
instance of aMutableArrayDataProvider
before thereturn
statement.const pieDataProvider: MutableArrayDataProvider<ChartItem["id"], ChartItem> = new MutableArrayDataProvider( [ { series: "Quantity in Stock", value: props.item?.quantity_instock }, { series: "Quantity shipped", value: props.item?.quantity_shipped }, ], { keyAttributes: "id" } );
-
Inside the
return
statement, beneath theh3
heading for Item Details, delete theoj-label
andoj-select-single
elements. Replace that code with a horizontal rule,oj-avatar
element, anddiv
elements to display databound item details.<hr class="hr-margin" /> <oj-avatar role="img" size="lg" aria-label={"product image for" + props.item?.name} src={props.item?.image?.replace("css", "styles")} class="float-right"></oj-avatar> <div id="itemName" class="data-name">{props.item?.name}</div> <div id="itemDesc" class="data-desc">{props.item?.short_desc}</div> <div id="itemPrice">{"Price: " + props.item?.price + " each"}</div> <div id="itemId">{"Item Id: " + props.item?.id}</div>
-
Replace the
id
,type
anddata
attributes in theoj-chart
element. Also add adiv
element surrounding theoj-chart
element.<div> <oj-chart id="pieChart" type="pie" data={pieDataProvider} animationOnDisplay="auto" animationOnDataChange="auto" hoverBehavior="dim" class="chartStyle"> <template slot="itemTemplate" render={chartItem}></template> </oj-chart> </div> </div> ); };
Save the file. Your code should look similar to
item-detail-container-tsx.txt
. -
Navigate to the
JET-Virtual-DOM-app/src/styles
directory and open theapp.css
file in an editor. -
Add the following style classes to the file that are used to format the item details.
.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; }
Save the file. Your code should look similar to
app.css
.
Task 5: View the Changes in the App
-
Return to the browser to view the changes in your virtual DOM app.
In the Item Detail Container, databound text fields and the Oracle JET Avatar and Chart components display the data for the SureCatch Baseball Glove item. However, the lists in the Activity Item Container and Activity Container do not respond to selection. In the next tutorial, you will add selection functionality.
Description of the illustration item_detail_container_updated.png
-
Close the browser window or tab that displays your running app.
-
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.
Create the detail view in an Oracle JET virtual DOM app
F72826-02
February 2024
Copyright © 2022, 2024, Oracle and/or its affiliates.