Before You Begin
This 60-minute tutorial shows you how to create an EnterpriseOne JET application based on a template that includes a single chart with a menu and query builder features.
Background
EnterpriseOne JET applications were developed as part of the UX One project. As a part of this effort, a template was created to facilitate the building of charts in JET. By following the template, the JET application will have the same look and feel, as well as the features, of all the other JET applications built for UX One.
The template eliminates the need for designing an HTML page to display the chart and to use the menu and query builder, but you will still need to get the data and load it correctly into the structures in order for the chart to display.
What Do You Need?
You will need JDeveloper 12.2.1 and the EnterpriseOne JET development environment download. Download "E1JETDeveloper_EnvironmentAndExamples" from the JD Edwards Update Center. To find it, use the following search criteria:
- Type: EnterpriseOne User Defined Objects.
- Release: All Releases.
- Platform: All Platforms.
- Search for Name: E1JET*.
Optionally, you may also want to install an optional data pack
intended for Demo Environments only. Since they replace business
data, use the data pack only for a demo environment: Data Pack 2
- Demo Data.
For more information on the data pack, please refer to the
overview document, included with the data pack, that describes
how to deploy the data pack to your environment.
Perform the prerequisites required to set up an EnterpriseOne Page JET development environment as described in the "Development Prerequisites" section of the "Setup for EnterpriseOne JET Development"" chapter in the same guide, which is located at:
https://docs.oracle.com/cd/E53430_01/EOTJT/get_started.htm#EOTJT550
Configure
and Test the AIS Server
- In JDeveloper, open the extracted contents of the
development environment download by opening
LocalJETDevEnv.jws.
Extracted Content - In JDeveloper, navigate to and open the e1pages folder.
e1 pages Folder - Open e1pagehelper.js to configure your AIS Server and make
these changes:
- Change AIS_HOST to the name of your AIS Server.
- Change AIS_PORT to the correct port.
- Change user name and password to be a
valid user and password on the HTML Server that is used by
the AIS Server.
Here is an example:
var LocalDevConfig = new function () { this.AIS_HOST = "server555.us.oracle.com"; this.AIS_PORT = "8866"; this.AIS_PROTOCOL = "http"; this.JAS_SERVER = null; this.USER_NAME = "JDE"; this.PASSWORD = "JDE"; this.ENVIRONMENT = null; this.ROLE = null; this.DEVICE_NAME = "localJet" this.NODE_JS_SERVER = null; }
- Register one or more browsers as external tools in
JDeveloper, and then test one or more of the included samples
by opening the folder and running the home.html file in a
browser.
See Adding External Tools to JDeveloper for more information.
e1 Pages Folder If the sample does not run, validate the AIS Server configuration in e1pagehelper.js. After successfully running the samples, you can proceed with building a new JET application. If you get the "Query definition is required" message, you can either create a query in the application for selection or use the QueryBuilder from the menu to create an ad hoc query.
Build
the New EnterpriseOne JET Application
Next, complete the following tasks in this section to use a sample template to build your JET application.
Copy P54HS260_NumberOfReportableCases and Update the E1AISCalls.js File
- Go out to the e1pages folder and copy one of the sample
folders (along with the three files contained in the folder)
into a new folder with a relevant name.
For this example, copy P54HS260_NumberOfReportableCases and rename it P13560_TotalCost.
- Refresh the JDeveloper project, and then open the new folder. You will only need to modify E1AISCalls.js if you are following the template.
- Change self.componentID. This value is used to persist any
menu and filter selections that the user has made so the next
time the user runs the JET application the settings are
recalled. This value must be a unique string <= 20
characters.
For this example, use P13560_TotalCost.
- Change self.objectName to be the application ID from which
the chart will get data. If there is no associated
application, this can be a table or business view.
For this example, use P13560.
- Change self.formName to the form of the application from
which the chart will get data. If objectName is a table or
view, this should be left blank.
For this example, use W13560A.
- self.labelObjectName is a reference to the EnterpriseOne
External Form used for getting translated labels. a. This will
not be used in this example and should be set to blank.
>self.labelObjectName="";
- Set self.isDataRequest. If true, and self.objectName is an
application, the data will be retrieved from the business view
associated with the application. Data retrieval from the
business view is faster than running the application and
aggregation can be used, which can significantly improve
performance. Using true for an application will bypass any
Event Rule logic in the application, so care should be taken
to ensure any data returned to render the chart is not
dependent on ER.
For this example, use true.
- Set self.hasVersions. This should be true if the application
has processing options. This is also important when using
queries since EnterpriseOne-saved queries are tied to a
specific version of an application.
For this example, use true.
- Set self.stackValue to ko.observable('off') or
ko.observable('on'). Turn this on if the chart will be a
stacked bar chart.
For this example, use off.
- Set self.chartType to ko.observable('bar'),
ko.observable('line') or ko.observable('pie').
For this example, use bar.
- Set self.orientationValue to ko.observable('horizontal') or
ko.observable('vertical').
For this example, use horizontal to build a horizontal bar chart.
- Move setTitleFieldText to the bottom of the initPage function. We will deal with the title last.
- self.xTitle and self.yTitle are used to label the x and y
axes. For this example, leave xTitle blank and set yTitle to
Cost:
self.xTitle = ko.observable(‘’); self.yTitle = ko.observable('Cost');
- Leave the self.xAxis and self.yAxis code, and delete the rest of the code in initPage except for setTitleFieldText.
Define 'Group By' Menu Field
This chart has a 'Group By' menu field that also appears in the title for override.
- You must define the values for selection:
self.selectValues = ko.observableArray([{value : 'prodFamily', label : 'Product Family'}, {value : 'prodModel', label : 'Product Model'}]);
- Define a change handler for the Group By dropdown:
self.groupByChangeHandler = function (context, valueParam) { if (valueParam.option == "value") { if (self.currentGroupByValue != valueParam.value[0]) { var drawer = self.offcanvasMap()["start"]; drawer.launcherId = "start"; drawer.displayMode = "overlay"; // if it's the active offcanvas, close it if (drawer !== self._activeOffcanvas) { self.savedGroupByValue(valueParam.value[0]); self.getData(); } } } };
- Set the default and saved values for the Group By:
self.savedGroupByValue = ko.observableArray(["prodModel"]); self.currentGroupByValue = 'prodModel';
- Add Group By to the menu:
setMenuFieldId(self, "groupByValue", "Group by", "ojSelect", self.savedGroupByValue, null, null, self.selectValues);
- Set the title and add Group By to the end:
setTitleFieldText("title1", "Total Cost by"); setTitleFieldInput(self, "dropDownValue", "ojSelect", self.savedGroupByValue, null, null, self.selectValues, "groupByChangeHandler", "150px");
After your changes, the code for initPage should look like this:
function initPage(ko, self) { self.componentId = "P13560_TCOST"; self.objectName = "P13560"; self.formName = "W13560A"; self.labelObjectName = ""; self.isDataRequest = true; self.hasVersions = true; self.stackValue = ko.observable('off'); self.orientationValue = ko.observable('horizontal'); self.chartType = ko.observable('bar'); self.xTitle = ko.observable(''); self.yTitle = ko.observable('Cost'); /* chart axes */ self.xAxis = ko.pureComputed(function () { return { title: self.xTitle() }; }); self.yAxis = ko.pureComputed(function () { return { title: self.yTitle() }; }); self.selectValues = ko.observableArray([{value : 'prodFamily', label : 'Product Family'}, {value : 'prodModel', label : 'Product Model'}]); self.groupByChangeHandler = function (context, valueParam) { if (valueParam.option == "value") { if (self.currentGroupByValue != valueParam.value[0]) { var drawer = self.offcanvasMap()["start"]; drawer.launcherId = "start"; drawer.displayMode = "overlay"; // if it's the active offcanvas, close it if (drawer !== self._activeOffcanvas) { self.savedGroupByValue(valueParam.value[0]); self.getData(); } } } }; self.savedGroupByValue = ko.observableArray(["prodModel"]); self.currentGroupByValue = 'prodModel'; setMenuFieldId(self, "groupByValue", "Group by", "ojSelect", self.savedGroupByValue, null, null, self.selectValues); setTitleFieldText("title1", "
Total Cost by
"); setTitleFieldInput(self, "dropDownValue", "ojSelect", self.savedGroupByValue, null, null, self.selectValues, "groupByChangeHandler", "150px"); }
Update jetTranslations and isEmpty Functions
- Clear out the contents of the jetTranslations function since the labels are hard-coded for this example, but do not delete it.
- Delete the isEmpty function, which is not used in this example.
Create getTotalCostData Function
- Change function getSafetyStatisticsForReportableCasesData to getTotalCostData in both the call in getE1Data and the function definition right below it.
- getTotalCostData is building the query and calling consumeData to prepare the data for the chart. First, the group by is set based on the drop-down selection. Since this is a data request, the view (V13550) is specified for the AIS call. The query will sum column AmountActual in F4801, which is part of the view. The filter criteria come from the Query selected in the menu as well as any query defined in the query builder.
- The code should look like this:
function getTotalCostData(self, callback) { var groupingCol = null; /* group by product model or product family */ if (self.savedGroupByValue() == 'prodModel') { groupingCol = "F4801T.PRODM"; } else if (self.savedGroupByValue() == 'prodFamily') { groupingCol = "F4801T.PRODF"; } var savedQuery = self.savedQueryValue; if (savedQuery == 'AllRecords') { savedQuery = ''; } var input = { aliasNaming : true, outputType : "GRID_DATA", findOnEntry : "TRUE", maxPageSize : "LocalJetVariables.maxPageSize", queryObjectName : savedQuery, targetName : "V13550", targetType : "view", dataServiceType : "AGGREGATION", aggregation : { aggregations : [{column : "F4801.AMTA", aggregation : "SUM"}], groupBy : [{column : groupingCol}], orderBy : [{column : groupingCol, direction : "ASC"}], /* currency trigger by company */ currency : { type : "CO", keyCols : ["F4801.CO"], currencyCols : ["F4801.AMTA"] } } }; if (self.adhocQuery) { input.query = self.adhocQuery; } self.currentGroupByValue = self.savedGroupByValue(); /* call AIS data service based on the above defined input */ callAISService(input, DATA_SERVICE, function (response) { // pass back error from AIS call if (response.message) { callback(false, response.message); } else { var dataArray = response.ds_V13550.output; if (dataArray.length > 0) { consumeData(self, response, function () { // pass back false for noData callback(false); }); } else { // pass back true for noData callback(true); } } }); }
- consumeData takes the response, which is the sum of all
AmountActual fields based on filter criteria grouped by either
Product Family or Product Model, and loads self.seriesValue
and self.groupsValue which are used to render the chart. It
also gets UDC descriptions of each group by key for display in
the label.
function consumeData(self, response, callback) { var dataSum = { 'groups' : [], 'series' : [] }; var dataArray = response.ds_V13550.output; var arrayLength = dataArray.length; var desc = null; var groupBy = null; /* Retrieve UDC descriptions */ if (self.savedGroupByValue() == 'prodFamily') { /* If Product family, retrieve descriptions from UDC 17/PA */ groupBy = "F4801T.PRODF"; var udcArray = []; var sy = '17'; var rt = 'PA'; } else if (self.savedGroupByValue() == 'prodModel') { /* If Product model, retrieve descriptions from UDC 17/PM */ groupBy = "F4801T.PRODM"; var udcArray = []; var sy = '17'; var rt = 'PM'; } for (i = 0;i < arrayLength;i++) { if (dataArray[i].groupBy[groupBy] == "") { dataArray[i].groupBy[groupBy] = " "; } setUDCArray(udcArray, sy, rt, dataArray[i].groupBy[groupBy]); } fetchUDCDescriptions(udcArray, false, function (udcDescMap) { dataSum['groups'][0] = ' '; for (i = 0;i < arrayLength;i++) { var desc = dataArray[i].groupBy[groupBy] + " - " + udcDescMap[dataArray[i].groupBy[groupBy]].desc; var total = dataArray[i]["F4801.AMTA_SUM"]; var items = [{value : total, label : desc, labelPosition : 'none', categories : [desc]}]; dataSum['series'].push( { 'name' : desc, 'items' : items }); } self.seriesValue(dataSum['series']); self.groupsValue(dataSum['groups']); callback(); }); }
- At this point, the application is ready to run by opening the home.html in a browser. When the application is run for the first time, it will select the first query in P13560 available for the user. If there is no query set up, you will see “Query definition is required.”
Set Up
a Query Using Query Builder
- You can set up a query using query builder by opening the menu (icon in the top left corner) and then selecting the filter icon. This will show all of the filter fields in P13560.
- You can add fields by clicking the + on the left, and then defining the criteria on the right. You can add multiple fields; they will be applied based on the Match All or Match Any selection. This query will be persisted once applied and will be used the next time the application is run by the user.
- By selecting Allow Override, the criteria will appear in the chart allowing for quick changes to the filter criteria.
- You can also run P13560 and create Queries in the application for the user. After doing so, those queries will appear in the Query drop-down of the menu for selection.
- The Application Query section shows the criteria of the selected Query in the menu if selected.
Import
the JET Application into EnterpriseOne as a Classic
EnterpriseOne Page
- After finishing your JET application, save all of the applicable files as a zip file.
- To create a Classic EnterpriseOne page, open EnterpriseOne, click the user personal information located on the right side of the banner bar at the top of the screen. Under the Personalization category, click the Manage Content - Classic Pages link.
- In the E1 Page Manager tab, enter the name, system code, and description, and then choose "Upload HTML Content" as the page type.
- Click the Browse button to locate the HTML zip file you want to upload, click the Upload button to add the content to the EnterpriseOne Page. You can also click the View Content button to see how the content displays in the EnterpriseOne Page.
- Save your page. After you click Save, the Available Languages, and the Language fields display. If you select Domestic Language from the drop-down menu, EnterpriseOne removes the Language field. If you select Add Translation from the drop-down menu, the Language field remains. In this field, enter the translation code in which you want the EnterpriseOne Name tab to display.
- You must first request to share the EnterpriseOne Page and receive View permissions from your system administrator before your page is available in runtime.
Create
an External Form for your JET Application
- If you want to add the application to a menu or Composed EnterpriseOne page, you must create an external form for it. In Form Design Aid, from the Form drop-down menu, select Create an External Form.
- On the General tab, enter a title for your form. Then, for the External Application Type, select JavaScript from the drop-down list.
- Enter the object name of the UDO in the External Application field. You can find the JET (JavaScript) object name by following these steps: First, on the EnterpriseOne screen, click the user personal information located on the right side of the banner bar at the top. Second, under the Personalization category, click the Manage Content link, then click Classic Pages. Third, select the name of the Classic Page that represents your JET object and click the information icon. The About form displays the EnterpriseOne Page information including the Object Name. You can copy the Object Name from here. Or you can also look up the object name in P98220W.
- Save your external form and you can now use it to add your JET application to a menu or Composed EnterpriseOne page.