Enhance and archive the Oracle JET web component

Introduction

A web component is a reusable piece of user interface that you can embed as a custom HTML element in your web app. Web components can contain Oracle JavaScript Extension Toolkit (Oracle JET) components, other web components, HTML, JavaScript, TypeScript, and Cascading Style Sheets (CSS). You use the Oracle JET tooling to create the web component, and you can use an Oracle JET starter template to generate the HTML and Typescript or JavaScript files that you modify to add and configure the web component.

In the previous tutorial, you created a web component that displays four input text fields. In this tutorial, you learn how to change the Item ID field to a read-only field, add a currency converter to the Item Price field, and add a length validator to the Item Description field. To pass values to these fields, define the attributes for the four input text fields in the HTML source of the web app. The attributes you use must have a corresponding property that is defined in the web component metadata file. You can pass static values to the attributes or use the data-bound expression syntax for one-way or two-way data binding between the web app and the web component.

Objectives

In this tutorial, you will enhance the web component with additional features in an Oracle JET web app. You also learn how to package the web component and prepare it to share with another app.

Prerequisites

Task 1: Edit Item ID to Read-Only

The Item ID field in your web component must be read-only. For accessibility purposes, replace the oj-input-text custom HTML element for the Item ID field with the oj-label-value custom HTML element. The oj-label-value element defines a slot that uses the oj-bind-text element to modify the Item ID field to read-only.

  1. Navigate to the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory and open the demo-update-item-view.html file in an editor.

  2. Locate the oj-input-text custom HTML element with the attribute value="ID number", and replace the oj-input-text element with the oj-label-value element.

    <oj-form-layout id="form-container" label-edge="[[labelEdge]]">
      <oj-label-value>
        <oj-label slot="label">Item ID</oj-label>
        <div slot="value">
          <oj-bind-text value="ID number"></oj-bind-text>
        </div>
      </oj-label-value>
      <oj-input-text value="Name" label-hint="Item Name"></oj-input-text>
    . . . 
    </oj-form-layout>
    
  3. Save the demo-update-item-view.html file.

    Your demo-update-item-view.html code should look similar to readonly-itemid.txt.

  4. Navigate to the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory and open the demo-update-item-viewModel.ts file in an editor.

  5. In the demo-update-item-viewModel.ts file, import the ojs/ojlabelvalue loader module after the entry that imports the ojs/ojinputtext module.

    "use strict";
    
    import * as ko from "knockout";
    import componentStrings = require("ojL10n!./resources/nls/demo-update-item-strings");
    import Context = require("ojs/ojcontext");
    import Composite = require("ojs/ojcomposite");
    import "ojs/ojknockout";
    import * as ResponsiveUtils from "ojs/ojresponsiveutils";
    import * as ResponsiveKnockoutUtils from "ojs/ojresponsiveknockoututils";
    import "ojs/ojformlayout";
    import "ojs/ojinputtext";
    import "ojs/ojlabelvalue";
    
  6. Save the demo-update-item-viewModel.ts file.

  7. In the terminal window, change to the JET_Web_Component_Application directory and run the app.

    npx ojet serve
    

    The browser displays the web component with the four input text fields in the Dashboard tab of your web app. The Item ID field is now a read-only field.

    Item ID field

  8. Leave the terminal window and the browser window or tab that displays your web app open.

    The npx ojet serve command allows you to make changes to your app code that are immediately reflected in the browser.

Task 2: Add a Currency Converter

Use a currency converter for the Item Price field.

  1. Navigate to the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory and open the demo-update-item-view.html file in an editor.
  2. Locate the oj-input-text custom HTML element with the attribute value="Price", and update it to use a currency converter that we’ll define in a later step. We enter 00 rather than Price as the placeholder value for the value property because the converter requires a valid number rather than a string.

    <oj-form-layout id="form-container" label-edge="[[labelEdge]]">
    ...
    <oj-input-text value="Name" label-hint="Item Name"></oj-input-text>
    <oj-input-text value="00" 
                   help.instruction="enter an amount with or without grouping separator"
                   converter="[[currency]]" 
                   label-hint="Item Price">
             </oj-input-text> 
    <oj-input-text value="Description" label-hint="Item Description"></oj-input-text>
    </oj-form-layout>   
    
  3. Save the demo-update-item-view.html file. Your demo-update-item-view.html code should look similar to currency-code-html.txt.

  4. Navigate to the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory and open the demo-update-item-viewModel.ts file in an editor.

  5. At the top of the demo-update-item-viewModel.ts file, import IntlNumberConverter from the ojs/ojconverter-number module:

    "use strict";
    
    import * as ko from "knockout";
    . . .
    import "ojs/ojinputtext";
    import "ojs/ojlabelvalue";
    import { IntlNumberConverter } from "ojs/ojconverter-number";
    
  6. In the ViewModel class, add a currency field for the currency converter that you’ll initialize in the next step.

    export default class ViewModel implements Composite.ViewModel<Composite.PropertiesType> {
       busyResolve: (() => void);
       . . . 
       currency: IntlNumberConverter;
    
    constructor(context: Composite.ViewModelContext<Composite.PropertiesType>) {
    . . .       
    
  7. In the constructor() method after the example observable entries, add the currency converter.

    constructor(context: Composite.ViewModelContext<Composite.PropertiesType>) {        
       . . .
       this.res = componentStrings["demo-update-item"];
    
       this.currency = new IntlNumberConverter({
          style: "currency",
          currency: "USD ",
          currencyDisplay: "code",
       });
    
  8. Save the demo-update-item-viewModel.ts file.

    Your demo-update-item-viewModel.ts code should look similar to currency-code-ts.txt.

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

  10. Enter the price in the Item Price field, and press Enter to verify the changes.

    Item ID field

    The price you enter shows a USD prefix. If you enter a non-numeric value, the Item Price field displays an error.

  11. Leave the terminal window and the browser window or tab that displays your web app open.

    The npx ojet serve command allows you to make changes to your app code that are immediately reflected in the browser.

Task 3: Add a Length Validator

Use a length validator for the Item Description field.

  1. Navigate to the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory and open the demo-update-item-view.html file in an editor.
  2. Locate the oj-input-text custom HTML element with the attribute value="Description", and update it to use a length validator that we’ll define in a later step.

       
    <oj-form-layout id="form-container">
    ...
    <oj-input-text value="00" 
                help.instruction="enter an amount with or without grouping separator"
                converter="[[currency]]" 
                label-hint="Item Price">
          </oj-input-text> 
    <oj-input-text
         value="{{lengthValue1}}" validators="[[validators]]"
         placeholder="Enter a description of 5-50 characters"
         label-hint="Item Description"
       ></oj-input-text>
    </oj-form-layout>
       
    
  3. Save the demo-update-item-view.html file.

    Your demo-update-item-view.html code should look similar to validator-code-html.txt.

  4. Navigate to the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory and open the demo-update-item-viewModel.ts file in an editor.

  5. At the top of the demo-update-item-viewModel.ts file, import AsyncLengthValidator from the ojs/ojasyncvalidator-length module:

       
    import * as ko from "knockout";
    . . .
    import { IntlNumberConverter } from "ojs/ojconverter-number";
    import AsyncLengthValidator = require("ojs/ojasyncvalidator-length");
    
  6. In the ViewModel class, add fields for the Knockout observables that you’ll initialize in the next step.

    export default class ViewModel implements Composite.ViewModel<Composite.PropertiesType> {
     busyResolve: (() => void);
     . . . 
     currency: IntlNumberConverter;
     lengthValue1: ko.Observable<string>;
     validators: ko.ObservableArray<AsyncLengthValidator<string>>;
    
  7. In the constructor method after the currency converter, add the length validator.

    constructor(context: Composite.ViewModelContext<Composite.PropertiesType>) {        
       . . .
       this.res = componentStrings["demo-update-item"];
    
       this.currency = new IntlNumberConverter({
          style: "currency",
          currency: "USD ",
          currencyDisplay: "code",
       });
    
       this.lengthValue1 = ko.observable("");
       this.validators = ko.observableArray([
          new AsyncLengthValidator({ min: 5, max: 50 }),
        ]);
        
    

    The length validator defines a minimum character length of 5 and a maximum character length of 50 for the Item Description field.

  8. Save the demo-update-item-viewModel.ts file.

    Your demo-update-item-viewModel.ts code should look similar to final-demo-update-item-viewModel-ts.txt.

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

  10. Enter a description in the Item Description field and press Enter, and then press Tab to clear the tooltip.

    Item ID field with validator

    If the description is longer than the set range, then the Item Description field displays an error.

  11. Leave the terminal window and the browser window or tab that displays your web app open.

    The npx ojet serve command allows you to make changes to your app code that are immediately reflected in the browser.

Task 4: Define the Web Component Metadata

The web component metadata file defines the web component’s required properties. Each input text field of the web component must have an associated property that will write back updates from the web component.

  1. Navigate to the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory and open the component.json file in an editor.

  2. Define the displayName and description metadata properties.

    {
    "name": "demo-update-item",
    "version": "1.0.0",
    "jetVersion": "^16.0.0",
    "displayName": "demo-update-item",
    "description": "A Web Component with form layout",
    ...
    }
    
  3. Below the description metadata property, use the camel-case naming convention to define the properties bound to the fields in the web component view.

    "description": "A Web Component with form layout",
    "properties": {
       "itemId": {
          "type": "number"
       },
       "itemName": {
          "type": "string",
          "description": "Description for the item-name attribute",
          "writeback": true
       },
       "itemPrice": {
          "type": "number",
          "writeback": true
       },
       "itemDesc": {
          "type": "string",
          "writeback": true
       }
    },
    

    The writeback property set to true ensures that these properties will receive updates from the web component that references the property in a two-way data binding expression.

  4. Save the component.json file.

    Your component.json code should look similar to component-json.txt.

Task 5: Define the Attributes and Attribute Values

Attributes of the web component element can reference the properties that you declared in the web component metadata file. In the HTML source of the web app, property references appear as case-insensitive HTML element attribute names with hyphens.

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

  2. In the demo-update-item element, define the attributes with static values for the four input text fields.

    <div class="oj-hybrid-padding">
       <div class="oj-panel oj-sm-margin-2x demo-mypanel">
          <h1 class="oj-header-border">Update Item Details</h1>
          <div>
             <demo-update-item item-id="34" 
                               item-name="John" 
                               item-price="3434.55" 
                               item-desc="This is an updated item">
                         </demo-update-item>
          </div>
       </div>
    </div>
    
  3. Save the dashboard.html file.

Task 6: Define the Web Component View

You can access any property defined in the web component’s metadata file by using the $properties variable of the view binding context.

  1. Navigate to the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory and open the demo-update-item-view.html file in an editor.
  2. In the custom HTML elements of the oj-form-layout element, bind the value attributes to the properties that are defined in the component.json file by using the $properties variable.

       
    <oj-form-layout id="form-container" label-edge="[[labelEdge]]">
    . . .
    <div slot="value">
          <oj-bind-text value="[[$properties.itemId]]"></oj-bind-text>
      </div>
    </oj-label-value>  
       <oj-input-text value="{{$properties.itemName}}" label-hint="Item Name"></oj-input-text>
       <oj-input-text value="{{$properties.itemPrice}}" 
          help.instruction="enter an amount with or without grouping separator"
          ...> 
       </oj-input-text>
       <oj-input-text
          value="{{$properties.itemDesc}}"
          . . .>
       </oj-input-text>
    </oj-form-layout>
       
    

    To define attribute values, use the [[]] syntax to define one-way data binding and the {{}} syntax for two-way data binding.

  3. Save the demo-update-item-view.html file.

    Your demo-update-item-view.html code should look similar to final-demo-update-item-view-html.txt.

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

    The browser displays the web component with the static values in the four input text fields.

    Item ID field

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

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

Task 7: Archive the Web Component

After you configure your web component, you must prepare the web component for other apps.

Open a terminal window, change to the JET_Web_Component_Application directory, and run the npx ojet package component command with the name of the component, demo-update-item, as a command parameter:

   npx ojet package component demo-update-item

Oracle JET packages the content of the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory into a ZIP file (demo-update-item_1-0-0.zip) that it creates in the JET_Web_Component_Application/dist directory. As part of the packaging task, Oracle JET transpiles the TypeScript code in the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory into JavaScript code. If, for example, you open the JET_Web_Component_Application/dist/demo-update-item_1-0-0.zip file, you’ll notice that it contains a demo-update-item-viewModel.js file that the Oracle JET tooling has transpiled from the demo-update-item-viewModel.ts file in the JET_Web_Component_Application/src/ts/jet-composites/demo-update-item directory.

You distribute the demo-update-item_1-0-0.zip file from the JET_Web_Component_Application/dist directory to consumers who want to reuse your web component in their web app. To use the web component in their web app, consumers extract the content of the ZIP file to a demo-update-item directory in their web app. We’ll go into detail about this latter task in the next tutorial.

Next Step

Proceed to the next tutorial in this module.

This tutorial is part of the module Reusable Web Components.

You can return to the learning path’s main page to access all the modules on building web apps.

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.