Tuesday, June 27, 2017

Oracle JET Modular Architecture Example

One of my favourite parts in Oracle JET - modular code structuring support. This allows to split application functionality into modules and reusable functions. In this post I will show how you could leverage Oracle JET modular architecture not only by implementing common code functions, but also by managing data maintained in common modules.

Let's jump to the example (download or browse through sample code on GitHub repository - JETModularArchitecture). Sample application is based on JET template. I have created two common modules - dashboardChartHelper and dashboardTableHelper. These modules define data structure to be displayed in the dashboard and provide API to manage this data from consuming module:


Both helper modules are imported into consuming module - dashboard:


Dashboard module defines variables (chart and table data), which are initialized from variables assigned with data structures in helper modules:


There are two wrapper functions, calling API functions from helper modules. API provides data manipulation logic, which changes chart data structure. Wrapper functions are invoked from dashboard UI:


Here is the implementation of API functions - data array changes:


What is great about such structuring - data and data changes logic can be encapsulated in common helper module. As soon as we have observable variable defined in consuming module (dashboard), which points to the method helper method (where data is changed) - changes are automatically visible on UI.

Here is the data coming from helper modules rendered in dashboard module:


Press on Add Group E button, this will call helper module API function to update data array cached in that module. In turn observable variable in dashboard module will be updated and data displayed on UI will be refreshed:


Press on Remove Group E button - chart data will be changed again:

Sunday, June 25, 2017

ADF BC Attribute - Collection Storage Mode Property

I would like to describe one interesting property for ADF BC attribute. This property is called Storage. There are two possible values: row (default) and collection. By default attribute value is saved in row storage, but alternatively it can be saved in collection storage. ADF BC implements collection storage using map which comes from session scope. This allows to keep value even between ADF BC requests, this is ideal for transient attributes.

Sample application (ADFBCCheckboxApp.zip) implements VO transient attribute to keep checkbox value:


VO is configured for Range Paging support. While user will navigate through UI table pages - VO range paging will re-execute and this will force VO replace rows (which will result in loosing transient attribute values):


This is how it will look like. User will select checkbox and then navigate to another table page:


After navigating back - checkbox value will be lost (range paging mode will re-execute VO rowset to bring rows belonging to current page):


To force transient attribute value to stay, go to Properties window for the attribute and scroll down to the last section. Select attribute called Storage:


Change value to collection. This will force ADF BC to store value for this attribute in session map:


Transient attribute value will stay, even when VO is re-executed in range paging mode and VO rowset is refetched:

Monday, June 19, 2017

Fixes for ADF Cloud User Experience Rapid Development Kit (RDK) UI Layout Issues

If you was evaluating Oracle RDK UI template, probably you noticed information popup coming up, when RDK home page is loaded. Popup is loaded through showPopupBehavior listener, which is executed on Welcome page load event. Such popup is not required in practice, and usually is disabled. But as soon as you disable it, there will be layout issues with Welcome page. User information widget will not align the name and menu navigation items will not be ordered correctly:


This is not nice. And you will get such behaviour only when popup is not loaded:


I looked into it in more detail and I saw there is a second HTTP PPR request executed, when popup is loaded. It seems this second HTTP request was triggering partial response and this was forcing UI to load correctly:


Fortunately I found a simple fix for that. Need to set layout="horizontal" for springboard panelGroupLayout component located in Welcome page:


This change makes job done and now Welcome page layout is rendered correctly from the start, even without loading popup and forcing second HTTP PPR request:


There is another issue - related to panelGridLayout usage in ADF Task Flows loaded through Film Strip page. You can check my previous example about customising/extending RDK template - Extending ADF Cloud User Experience Rapid Development Kit (RDK). Let's assume use case with ADF Task Flow implementing two fragments (search and edit functionality):


Search screen renders ADF list implemented using panelGridLayout:


Navigate to edit screen:


Try to navigate back to search screen, you will get empty list displayed:


Fix is simple. RDK is using property stretchChildren="first" in FilmStrip page and this seems to break UI layout for regions with panelGridLayout component:


Remove stretchChildren="first" property from FilmStrip page, showDetailItem component assigned with id="sdi1":


With this fix applied, try to navigate from edit to search:


This time search page layout with panelGridLayout component is displayed as it should:


Download extended RDK application code with applied fixes - AppsCloudUIKit_v3.zip.

Wednesday, June 14, 2017

Nice Trick to Get ADF LOV Description Text

I will tell you about nice trick to display LOV description. Usually you would create separate attribute in VO for LOV description and base LOV on this attribute (read about it in my previous post - Defining the LOV on a Reference Attribute in Oracle ADF 11g). But there is one more way - it makes it much faster to define LOV on description, but you should be aware about additional SQL statement executed to fetch description text.

You could set converter for ADF UI LOV, and then LOV component would use description by itself, without any additional configuration.

It is important to set correct order for LOV display attributes. Make sure to set description attribute to be first in the list for converter approach to work:


Go to ADF UI LOV component and set converter property. This must point to binding object, converter expression:


What you get - LOV field displays description, converter is able to mask ID value behind it:


It offers nice usability option - you could start typing description, press tab and value will be auto completed (if autoSubmit is set to true):


Behind the scenes it executes LOV SQL to get description text (this SQL is executed on page load too, which is not ideal when you have many LOV fields - in such situation is better to use separate attribute for description in the same VO):


When LOV value is changed and changes are saved, ADF BC updates ID value only (as expected):


Download sample application - ADFLovDescriptionApp.zip.

Saturday, June 3, 2017

Running ADF BC REST Service Together with ADF Faces Application

ADF 12c provides out of the box support for ADF BC REST API. It is straightforward to create ADF BC REST service and run it. But what if you would like to expose ADF BC REST for existing ADF application with ADF Faces UI. This could be useful if there is a requirement to handle ADF Bindings access to ADF BC along with light ADF BC REST service API implementation for Oracle JET or other JavaScript clients. The same ADF application could handle two types of client access - ADF Faces and REST.

When you create ADF BC REST application, JDeveloper creates REST Model and WebService projects. Technically speaking, if you have existing ADF application with Model and ViewController, you could add third project for REST Web Service by yourself. Two configuration files are required - web.xml and weblogic.xml (if ADF Security is enabled):


ADF BC REST is exposed to the client through ADF servlet. It doesnt work to enable ADF BC REST servlet in ADF Faces project web.xml. This requires to have separate WAR deployment for ADF BC REST and different context root.

ADF Faces and ADF BC REST are sharing the same ADF Security context and this means we are using the same set of Application Roles for both.

In my example, ADF Bindings are mapped with Employees VO instance - this brings data to be displayed in ADF Faces:


The same VO instance is exposed through ADF BC REST:


ADF BC REST servlet is defined in REST project web.xml. It doesnt work to define it in the same web.xml where ADF Faces are configured - context conflict error comes on runtime. Thats the reason why I have separate WAR for ADF BC REST:


There is one WAR for ADF Faces app and one for ADF BC REST. Both WARs are packaged into single EAR. This means there is one deployment, but two context roots, one for each WAR:


If you download my sample app and want to run it, make sure to build REST project first:


Then click Run for ADF Faces app - ADF BC REST WAR will be packaged automatically (if you deploy it on standalone, simply build EAR - it will include both WARs):


We can see it in the deployment log - both WARs are packaged into single EAR:


This is the result - ADF Faces UI is accessed through adfapp context root:


ADF BC REST from the same application is accessed through restapp context root, authenticated with the same ADF Security context as ADF Faces app:


Download sample application - ADFFacesRESTApp.zip.

Tuesday, May 30, 2017

ADF PopUp Event Context Launcher

I will describe how you could use ADF popup event context to pass parameters into popup. This could be useful if you want to develop reusable popup, which should accept different type of parameters from various launcher components.

In this example - popup is loaded from context info. Launcher component - output text is assigned with attribute, reading its value from binding. Our goal is to pass attribute value into popup:


In order to be able to read attribute value from launcher parent component, make sure to set eventContext="launcher" for ADF popup:


You can reference parent UI component from launcher property, this can be done in popup fetch listener - where value will be copied to managed bean property:


We could process launcher parent component in managed bean, extract values, etc.:


Value retrieved from popup launcher is displayed in the popup:


Download sample application - PopUpEventContextApp.zip

Thursday, May 18, 2017

Oracle JET Hybrid - NavDrawer Template Menu/Header Structure

Oracle JET provides NavDrawer template for Web and for Hybrid. Read how to create JET Hybrid application based on template - Create a Hybrid Mobile Application. There is significant difference in NavDrawer template implementation when we compare Web and Hybrid application.

Hybrid template draws menu structure on top of the form. Web template is pushing form to the right, when menu is opened. Such approach works fine on the Web, but you would see significant UI lag each time when menu item is selected. Probably thats the reason why hybrid NavDrawer template draws menu on top of the form - visually this provides better performance when switching between menu items. Menu is rendered on the top of the form in JET Hybrid Nav Drawer template:


Form is loaded instantly, when menu item is selected. Header in JET Hybrid NavDrawer template stays fixed, it doesnt scroll. This gives good opportunity to put there common actions:


NavDrawer template in JET Web application moves form to the right, when menu is opened - thats the main visual difference when comparing to NavDrawer Hybrid:


Index page of NavDrawer hybrid template is almost identical to Web NavDrawer, except that it doesn't contain header part. Header is implemented separate module:


I have customized default header implementation with additional items - logo and user preferences:


Header module is constructed in appController, this is how it is generated by default. If we want to have access to variables/functions from appController in the header, we need to create a mapping:


Every module must include div with fixed top JET CSS class (thats why it doesnt scroll and stays on top), where you would copy header code:


Header is bind with module, which is defined by headerConfig variable (must be located in each module) - which is initialized in appController:


Thats all about menu/header implementation.

Let's learn how to push update to Google Play. Make sure to increase application version in Cordova config.xml file:


Go to Google Play and upload new APK, it will be parsed and Google Play automatically will deactivate previous version:


You can initiate roll-out to production:


This will push new release to Google Play. Users will be automatically notified about new version:


Version 2 of our JET Hybrid app is available on Google Play: