Create a form to create data records in an Oracle JET virtual DOM app
Introduction
This tutorial shows you how to use your Oracle JavaScript Extension Toolkit (Oracle JET) virtual DOM app to create a data record and submit it to a REST service.
Objectives
In this tutorial, you will learn how to write data to a REST service.
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, Fetch Data from a REST API in an Oracle JET Virtual DOM App
Task 1: Create Components to Manage Form Information
Create new components that will display a button used to invoke the functionality to create a new record. An ItemActionsContainer
component holds the button that allows virtual DOM app users to invoke the CreateNewItemDialog
component that contains the functionality to create a new record.
-
Navigate to the
JET-Virtual-DOM-app/src/components/ActivityItem
directory, create a newCreateNewItemDialog.tsx
file, and open it in an editor. -
Add the placeholder entries that define a function name (
CreateNewItemDialog
) for the new component.import { h } from 'preact'; type Props = { message?: string; }; const CreateNewItemDialog = (props: Props) => { return ( <div class="oj-web-applayout-max-width oj-web-applayout-content"> <p>content</p> </div> ); }; export default CreateNewItemDialog;
-
In the same directory, create a
ItemActionsContainer.tsx
file and open it in an editor. -
Add the placeholder entries that define a function name (
ItemActionsContainer
) for the new component.import { h } from 'preact'; type Props = { message?: string; }; const ItemActionsContainer = (props: Props) => { return ( <div class="oj-web-applayout-max-width oj-web-applayout-content"> <p>content</p> </div> ); }; export default ItemActionsContainer;
Task 2: Handle Opening the Dialog
Import the Oracle JET modules and declare the functions that will enable your Oracle JET virtual DOM app to successfully open a dialog.
-
At the top of the open
ItemActionsContainer.tsx
file, import the Oracle JET module for the Button component.import { h } from 'preact'; import 'ojs/ojbutton';
-
Define a
create
property in theProps
type alias to manage opening a create dialog.import { h } from 'preact'; import 'ojs/ojbutton'; type Props = { create: () => void; };
-
In the
return
statement, replace the existingdiv
element with a newdiv
element that renders anoj-button
element with anonojAction
attribute that references thecreate
property.const ItemActionsContainer = (props: Props) => { return ( <div> <oj-button id="createButton" onojAction={props.create}> Create </oj-button> </div>
Save the
ItemActionsContainer.tsx
file. Your code should be similar toItemActionsContainer.tsx.txt
-
At the top of the open
CreateNewItemDialog.tsx
file, import the Oracle JET modules for the Dialog component andMutableRef
hook.import { h } from 'preact'; import 'ojs/ojdialog'; import { ojDialog } from 'ojs/ojdialog'; import { MutableRef } from 'preact/hooks';
-
Define
isOpened
andcloseDialog
properties in theProps
type alias.type Props = { isOpened: boolean; closeDialog: (ref: MutableRef<ojDialog>, type: string) => void; };
-
In the
return
statement, replace the existingdiv
element with aspan
element that wraps theoj-dialog
custom element.return ( <span> <oj-dialog id="createDialog" ref={createDialogRef} dialogTitle="Create New Item" onojClose={closeDialog} cancelBehavior="icon"> <div slot="body"> <p>dialog open</p> </div> </oj-dialog> </span> );
-
At the top of the
CreateNewItemDialog.tsx
file, import theuseRef
anduseEffect
Preact hooks.import { h } from 'preact'; import { useRef, useEffect } from 'preact/hooks'; import 'ojs/ojdialog'; import { ojDialog } from 'ojs/ojdialog';
-
Before the
return
statement, declare thecreateDialogRef
andcloseDialog
variables that will hold the reference that theuseRef
Preact hook retrieves.const CreateNewItemDialog = (props: Props) => { const createDialogRef = useRef<ojDialog>(null); const closeDialog = () => { props.closeDialog(createDialogRef as MutableRef<ojDialog>, "create"); } return (
-
Also before the
return
statement, use theuseEffect
hook to write an expression that sets a value for theisOpened
property.const CreateNewItemDialog = (props: Props) => { const createDialogRef = useRef<ojDialog>(null); const closeDialog = () => { props.closeDialog(createDialogRef as MutableRef<ojDialog>, "create"); } useEffect(() => { props.isOpened ? createDialogRef.current?.open() : createDialogRef.current?.close(); }, [props.isOpened]); return (
Save the
CreateNewItemDialog.tsx
file. Your code should be similar toCreateNewItemDialog-1.tsx.txt
-
Navigate to the
JET-Virtual-DOM-app/src/components/ActivityItem
directory and open theActivityItemContainer.tsx
file. -
At the top of
ActivityItemContainer.tsx
, import theItemActionsContainer
andCreateNewItemDialog
components that you just created and also import the modules for the Oracle JET Form Layout and Input Text components.import ItemActionsContainer from "./ItemActionsContainer"; import CreateNewItemDialog from "./CreateNewItemDialog"; import "ojs/ojformlayout"; import "ojs/ojinputtext"; import { ojDialog } from "ojs/ojdialog"; import { MutableRef} from "preact/hooks"
-
After the
ActivityItemContainer
function declaration, create variables that use Preact’suseState
hook and a function (openCreateDialog
) to open the dialog.We also include an entry that manages the open state of an Edit dialog that we create in a later tutorial.
const ActivityItemContainer = (props: Props) => { const [isCreateOpened, setIsCreateOpened] = useState<boolean>(false); const [isEditOpened, setIsEditOpened] = useState<boolean>(false); const openCreateDialog = () => { console.log("CreateNewItemDialog called"); setIsCreateOpened(true); };
-
Before the
return
statement, also include a function that closes an open dialog.const handleDialogClose = (ref: MutableRef<ojDialog>, type: string) => { type === "create" ? setIsCreateOpened(false) : setIsEditOpened(false); ref.current.close(); }; return ( <div id="activityItemsContainer" class=. . .>
-
In the
return
statement, include the newly-createdItemActionsContainer
andCreateNewItemDialog
components.return ( <div id="activityItemsContainer" . . .> <div id="container"> <h3>Activity Items</h3> <ItemActionsContainer create={openCreateDialog} /> <CreateNewItemDialog isOpened={isCreateOpened} closeDialog={handleDialogClose} />
Save the
ActivityItemContainer.tsx
file. Your code should be similar toActivityItemContainer-1.tsx.txt
Task 3: Handle Submitting the Dialog Input
-
Navigate to the
JET-Virtual-DOM-app/src/components/ActivityItem
directory and open theCreateNewItemDialog.tsx
file. -
At the top of the open
CreateNewItemDialog.tsx
file, import Preact’suseState
hook.import { ojDialog } from 'ojs/ojdialog'; import { MutableRef, useRef, useEffect, useState } from "preact/hooks"
-
In the
Props
type alias, define acreateNewItem
property.type Props = { isOpened: boolean; closeDialog: (ref: MutableRef<ojDialog>, type: string) => void; createNewItem: (data: Partial<Item>, ref: MutableRef<ojDialog>) => void; };
-
Define an
Item
type alias that includes fields for the data that you send to the REST service.type Item = { name?: string | undefined; short_desc?: string; price?: number; quantity_shipped?: number; quantity_instock?: number; };
-
Find the
oj-dialog
custom element in thereturn
statement and replace the content of<div slot="body">
with anoj-form-layout
element andoj-input-text
elements for the input fields to create a new item. Also include a<div slot="footer">
with anoj-button
element.<oj-dialog id="createDialog" ref={createDialogRef} dialogTitle="Create New Item" onojClose={closeDialog} cancelBehavior="icon"> <div slot="body"> <oj-form-layout> <oj-input-text id="name" labelHint="Name" onvalueChanged={onChangeHandler}></oj-input-text> <oj-input-text id="price" labelHint="Price" onvalueChanged={onChangeHandler}></oj-input-text> <oj-input-text id="short_desc" labelHint="Description" onvalueChanged={onChangeHandler}></oj-input-text> <oj-input-text id="quantity_instock" labelHint="Quantity: In-Stock" onvalueChanged={onChangeHandler}></oj-input-text> <oj-input-text id="quantity_shipped" labelHint="Quantity: Shipped" onvalueChanged={onChangeHandler}></oj-input-text> </oj-form-layout> </div> <div slot="footer"> <oj-button id="submitBtn" onojAction={createItem}>Submit</oj-button> </div> </oj-dialog>
-
Before the
return
statement, make use of theuseState
hook and include theonChangeHander
andcreateItem
functions that the Oracle JET elements reference.const [formData, setFormData] = useState<Partial<Item>>({}); const onChangeHandler = (event: any) => { setFormData({ ...formData, [event.currentTarget.id]: event.detail.value, }); } const createItem = () => { console.log("data: " + JSON.stringify(formData)); props.createNewItem(formData, createDialogRef as MutableRef<ojDialog>); }; return ( <span>. . .
Save the
CreateNewItemDialog.tsx
file. Your code should be similar toCreateNewItemDialog-2.tsx.txt
-
Navigate to the
JET-Virtual-DOM-app/src/components/ActivityItem
directory and open theActivityItemContainer.tsx
file. -
In the
return
statement, update theCreateNewItemDialog
class to include thecreateNewItem
method that you defined in theCreateNewItemDialog
component.<CreateNewItemDialog isOpened={isCreateOpened} createNewItem={createItem} closeDialog={handleDialogClose} />
-
Before the
return
statement, include a newcreateItem
function that creates a new item and sends it to the backend REST service.const createItem = async (data: Partial<Item>, createDialogRef: MutableRef<ojDialog>) => { //process create command and close dialog on success if (data?.name) { let quantity = Number(data.quantity_instock) + Number(data.quantity_shipped); const row = { name: data.name, short_desc: data.short_desc, price: data.price, quantity_instock: data.quantity_instock, quantity_shipped: data.quantity_shipped, quantity: quantity, activity_id: props.selectedActivity?.id, image: "css/images/product_images/jet_logo_256.png", }; // Create and send request to REST service to add row const request = new Request(restServerURLItems, { headers: new Headers({ "Content-type": "application/json; charset=UTF-8", }), body: JSON.stringify(row), method: "POST", }); const response = await fetch(request); const addedRow = await response.json(); activityItemDataProvider?.refresh(); // Close dialog console.log("Created new item"); createDialogRef.current.close(); } };
-
After the
ActivityItemContainer
function declaration, define a variable that references the URL to use to send the item to the REST service.const ActivityItemContainer = (props: Props) => { const activityItemDataProvider = props.data; const restServerURLItems = "https://apex.oracle.com/pls/apex/oraclejet/lp/activities/" + props.selectedActivity?.id + "/items/";
-
Save the
ActivityItemContainer.tsx
file. Your code should be similar toActivityItemContainer-2.tsx.txt
Task 4: Test the Code and Create a Record
-
In the terminal window, change to the
JET-Virtual-DOM-app
directory and run the virtual DOM app.npx ojet serve
-
In the browser, view the dynamic changes in your virtual DOM app.
-
In the virtual DOM app, click on the Baseball activity.
-
Click Create.
The Create New Item dialog opens.
-
Fill in details for a new item.
- Name:
SureFire Ball (Set of 4)
- Price:
20.5
- Description:
Canvas balls for practice
- Quantity: In-Stock:
35
- Quantity: Shipped:
61
- Name:
-
Click Submit.
The section refreshes and the item is part of the list of Baseball activity items.
-
Click the SureFire Ball (Set of 4) item in the list and view its details.
-
Close the browser window or tab that displays your running virtual DOM 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 a form to create data records in an Oracle JET virtual DOM app
F70628-03
July 2024