JET In Typescript

Oracle® JavaScript Extension Toolkit (JET)
15.1.0

F83698-01

Overview

This guide explains how to use JET in your Typescript project. JET's Typescript type definitions are bundled with the JET npm package. These type definitions get installed automatically when you install the JET library from npm. To get the latest recommended tsconfig.json in an existing Javascript or Typescript JET project, you can run the following command:

ojet add typescript
To create a new typescript JET project from one of the JET starter templates, you can run the following command:
ojet create AppName --template=(blank|basic|navbar|navdrawer) --typescript

JET Typescript type definitions include definitions for JET elements as well as non element classes, namespaces, interfaces etc. The below sections explain how each of these modules can be imported in to your project and used.

Working with JET Elements

JET Elements are exported as Typescript interfaces. These interfaces are useful in typechecking the element APIs but have no run time impact.
Import a JET element in your viewmodel, as below,

import {ojInputText} from "ojs/ojinputtext";
Please be aware that Typescript compiler excludes 'no side effect' imports when transpiled to javascript. So for your viewmodel to load all the required component modules, please double import the component as below.
import {ojInputText} from "ojs/ojinputtext";
import "ojs/ojinputtext";
Some of the JET element modules contain multiple components. If you need to work with them, you can import them as below
import {ojInputText, ojInputPassword} from "ojs/ojinputtext";
import "ojs/ojinputtext";

Cast your HTML element to JET Element

To work with a component instance in your view model, you must typecast the element to the correct JET Element type. An example below:-

let myInputText = document.getElementById('input') as ojInputText;
Please note that, some of the JET Elements are Generic types. So you will have to specify the type details while casting. You can see the generic parameter details of component under 'Generic Parameters' subsection in the component API page. For example, ojTable takes two parameters- the type of key and data of your dataprovider. The example below shows how to cast to a table whose dataprovider's key is number and data is object type.
 let tableElement = document.getElementById('table') as ojTable<number, object>;

Using Element APIs

To get a property value,

let myValue = myInputText.value;
To set a property, you will use the below simple format in most cases,
myInputText.value = "Hello There";
But some of the JET element properties have different getter and setter types. Example expanded property of Accordion. In such cases if you want to set the property to a type defined only in SetterType, you should use the 'set' method as below. (Please note that this method can be used to set any property even if it does not have a different Setter Type)
//Note that the expanded always returns Array<{id?: string, index?: number}>.
//But you are allowed to set an array of number or string as expanded.
//The following code will fail.
//myAccordion.expanded' = [1,2,3];
//But you can set expanded to a number array using set method,
myAccordion.set('expanded', [1,2,3]);
To reset a property value to its default, use "unset" method as below.
myAccordion.unset('expanded');
Invoking a component method looks like
myInputText.refresh();
Attaching an event listener to the component

//Create your listener function
myListener = (evt: ojInputText.ojAnimateStart) => {
}
//You can attach this to your component as below,
myInputText.addEventListener("ojAnimateStart", this.myListener);
In JET application you will often bind a variable to your component in the html and initialize or update it in your view model. The below example shows how to make such variables type safe.

//HTML code,
<oj-navigation-list data="[[navDataSource]]"
   on-selection-changed="[[selectionChange]]">
</oj-navigation-list>

//Your view model
import {ojNavigationList} from 'ojs/ojnavigationlist';
import "ojs/ojnavigationlist";

class HeaderViewModel {
  navDataSource: ojNavigationList<string, object>['data'];
  selectionChange: (event: ojNavigationList.selectionChanged<string, string>) => any;

  constructor() {
    let self = this;
    //data source will now be typechecked to ensure it is of type DataProvider<string, object>
    self.navDataSource = new ArrayDataProvider(HeaderViewModel.navData, { keyAttributes: 'id'});
    //selection change callback handler's event parameter will now be typed to let you access properties
    //like event.detail.value, event.detail.previousValue etc.
    self.selectionChange = (event) => {
      let newVal = event.detail.value;
      if (newVal !== self.router.stateId()) {
        self.router.go(newVal);
      }
    }
  }
}

Working with non element classes

JET non element classes, namespaces and interfaces are grouped in to vaious modules. Every module either returns a single class or multiple classes in an umbrella object. To use a module correctly, it is important to know what is returned by it. You can find details about how to import a class/interface from a module in to your typescript project in the 'Typescript Import Format' section of the class/interface doc.
Here is an example of a module which returns a class and how to use it,

import ArrayDataProvider = require('ojs/ojarraydataprovider');
let dataprovider = new ArrayDataProvider([{value: 'R', label: 'Red'},{value: 'B', label: 'Blue'}], {keyAttributes: 'value'});
myTableElment.data = dataprovider
An example of a namespace which returns an object with all static methods,
import * as Logger from "ojlogger";
Logger.log("The button is clicked");
In the below example, we are using validation-base module to create a validator. This module returns an umbrella object with multiple classes in it. Please note how the import syntax has changed
import {Validation, LengthValidatorFactory} from "ojs/ojvalidation-base";
let factory = Validation.validatorFactory('length') as LengthValidatorFactory;
let validator = factory.createValidator({max: 10});
myTextComponent.validators = [validator];