Wednesday, June 22, 2016

Red Samurai Oracle JET Mobile Hybrid App Live on Android

We have implemented Oracle JET mobile hybrid app in less than 30 minutes and deployed it to Android device. This was done as a demo to the customer and could prove Oracle JET offers effective approach for hybrid mobile app development. Development process isn't much complicated with JET once you familiarize yourself with JavaScript development process and learn how to interact with REST services.

Red Samurai app based on JET (using out of the box JET template NavDrawer) is deployed on Android:


Out of the box JET allows to implement form validation, multi select and date entry controls:


Charts are rendered fast, animation is not lagging behind:


JET offers various grouping controls, to arrange content on the page:


Various types of charts can be rendered in responsive layout dashboard and are resized out of the box:


JET allows to build more complex screens, with large amount of UI components:


I'm happy with JET mobile hybrid offering. Stay tuned for more posts on this topic in the future.

Tuesday, June 21, 2016

Go Mobile with Oracle JET As Easy As 1 2 3

Oracle JET allows to build and run mobile hybrid applications. It is using Cordova to run on mobile device and provide access to device services. This is cool and what is great about it - it allows to get you started with mobile development in minutes. Besides all this - it is free.

I will describe steps I followed, to generate JET mobile hybrid app and run it in local browser (in the next posts I will describe how to run it on simulator and actual device).

First of all you must install Node.js and npm on your machine. This will allow to run shell environment to execute various commands related to JET app generation, setup, build and deployment. Read this article and you will learn how to do it - Installing Node.js and updating npm.

Next follow Step 1 and install Cordova in Step 5 from JET Get Started list.

You are ready to generate JET mobile hybrid app at this point. If you are on Mac OS, don't forget to use sudo, otherwise there will be permission related errors. Run Yeoman to generate the app:

yo oraclejet:hybrid JETMobileApp --template=navBar --platforms=ios

At this stage you can choose predefined JET template, here I'm generating it with navBar template for  iOS platform. It must complete with Done, without errors message:


Make sure to navigate to app folder with cd AppName:


Build generated app with grunt. Command I was using to build it for iOS (you can see from the log, it is producing *.app file, which can be deployed to mobile device as application):

grunt build:dev --platform=ios

It must complete with Done, without errors:


Run application to test in local web browser. See more options (deploy to simulator or device) here - Serve a Hybrid Mobile Application with Grunt. Use grunt command:

grunt serve --platform=ios --web=true --disableLiveReload=true

I'm running it with disableLiveReload=true for a reason. It seems like live reload initialization takes long time to start. Template based JET mobile hybrid app is started (in web browser, for testing):


Generated project can be opened in NetBeans, simply select project from the folder:


Under src folder you will find JET content. Try to change text in any of the generated pages:


Rebuild and serve application, you should see changes deployed for customers page in this case:

Saturday, June 18, 2016

ADF BC Range Paging and ADF UI Table Pagination Use Case

ADF UI table pagination and ADF BC range paging sounds like a perfect combination. But to make it work perfect, a bit of extra effort is required. In the case of search/edit implementation, it can't remember updated record when navigating back to search screen (VO runs with Range Paging and UI table is displayed with pagination). I will explain how to solve it and show how to keep UI table displaying current page and prevent jumping to the first page.

Here is the working use case (download sample application - SearchEditApp.zip). Navigate to any page except first in UI table and select a record:


On edit, selected record should be opened in the fragment. Both buttons Save and Close/Close would return back to search screen, where current record and page should be preserved:


Close button will trigger Rollback operation, but current row should not be lost (see solution here: ADF Rollback Operation and Stay On Current Row):


Current row and page remains selected on return to search fragment:


Huge advantage of Range Paging mode for VO - faster navigation between UI table pages. This is especially important now, when we support pages. It is much easier for the user, to navigate to the last page (one click, without scrolling). We must ensure fast navigation in the table. This can be achieved with Range Paging - it will force VO to generate SQL query with ROWNUM and what is also very important - it will fetch only a subset of data (by default, ADF BC would fetch all rows until last, when navigating to the last page). Here we navigate to the last page:


Example of SQL query generated by VO enabled with Range Paging and subset of row data fetched for last page:


To force UI table to return display to correct page (navigation to search from edit), when Range Paging is enabled in VO - make sure to set first property for UI table (see solution here: ADF Rollback Operation and Stay On Current Row). We should keep track of current range start before navigating away from search screen and reset it back to the same value, when navigating from edit. I'm keeping this value in pageFlowScope variable managed through the bean method invoked on edit:


This is the method - it keeps track of current range start and updates pageFlowScope variable (later referenced from first property on UI table):


Bonus - see example how to refresh VO data (this is useful, when you want to display latest data to the user, before he starts editing it) and keep current row. When Range Paging is enabled, current row can be retained by re-setting current row key obtained from iterator binding (this executes SQL with find row by key and returns only current row):

Tuesday, June 14, 2016

Using the Oracle JET QuickStart Template

I will show in the post, how you can create single page applications with multiple modules in Oracle JET. As a starting point, you should use the Oracle JET QuickStart template, read about it here. This template comes with sample structure and you could follow it to split application functionality into different groups.

Download sample application, which is based on Oracle JET QuickStart template - JETCRUDApp_v10.zip (you must run ADF BC REST application in JDEV 12.2.1 and JET in NetBeans 8). QuickStart application is extended with new module, it contains CRUD implementation in JET (read more here).

I have slightly modified template and removed boxes for navigation and complimentary areas. It renders main content block stretched on the screen:


Under Employees tab, CRUD functionality to manage employees data is rendered. This includes CRUD functionality described in my previous posts about JET (see link above). Now it is part of real JET application:


Let's take a look into structure. QuickStart template comes with structure, where each module is separated into HTML/JavaScript files. There is a group available for employees CRUD - employees.html and employees.js:


Main page logic is implemented in index.html. This file includes page structure and references block with dynamic module (loaded through menu structure):


List of available modules is registered in main.js file router:


JET CRUD functionality use case HTML part is copied into employees.html file (this will be loaded through main.js router):


JavaScript part is copied into employees.js file:


JavaScript logic is changed to handle table row selection event through JavaScript listener method. Constructed employees view model is returned to be accessible from the router:

Saturday, June 11, 2016

How To Control Row Removal in ADF BC

There is a flaw in ADF BC remove operation. Row could be successfully removed in ADF BC - it dissapears from UI as well, but if there is DB integrity constraint violation - row is not removed in DB and error message is displayed to the user. This could be misleading to the user, he sees message about failed removal, but at the same time row is not present anymore.

Easier to explain with example. Let's imagine we want to remove IT_PROG job (there are employees assigned with this job and row removal would fail in DB):


On delete, row is removed from ADF BC and UI, but operation fails in DB and error is returned:


ADF BC completes row removal before row is really removed in DB. This is why ADF BC doesn't really know about failed row removal and is not able to keep it.

Technically such behavior is valid, but hardly understandable for business user. If row is not removed it should stay in the application.

We could solve it by overriding doDML method and executing row removal through custom method defined in VO implementation class. In doDML we can catch DML constraint exception during delete and execute refresh for removed row. Removed row is accessible in doDML, it is not dead yet. Calling refresh would allow to fix row state. We should throw exception and catch it in VO implementation class method, to refresh rowset and set back current row:


Custom method to execute remove in VO implementation class. Current row key is saved before remove and restored in case of exception. We must call executeQuery to refresh rowset, before setting back current row. In this example, commit is called right after row is removed. This allows to produce DB constraint error and process it in the context of VO. You may implement similar logic from global commit method, in such case you would need to include information about VO to be refreshed into exception message (raised in doDML):


Try to remove the same IT_PROG row now:


Failed row removal message is displayed and row remains in the application:


Download sample application - ADFDeleteControlApp.zip.

Thursday, June 9, 2016

UKOUG Slides - Forms, ADF and JET a Non-Aggression Pact

Florin Marcus was presenting topic on Forms modernization during UKOUG Development SIG seminar in London. Session was based on our production experience from recent Forms modernization project to ADF 12c and Alta UI.

Highlights:

- Who integrates Forms and ADF?

- Java Plugin to be Discontinued. Consequences for Oracle Forms.

- Why Yet Another Web Framework? Oracle JET.

- Forms and ADF and JET - Business Integration Patterns

- Forms Developer's perspective: life after learning ADF

Go through the slides and learn more about it:

Tuesday, June 7, 2016

Oracle JET Executing Dynamic ADF BC REST URL

I'm going to explain how to call ADF BC REST service from JET API and how to control parameters passed through to REST URL. Most of the time, REST should return data based on different parameter values, URL is not static. I will be exploring two cases - search functionality, where parameter value is entered by the user and LOV functionality, where current employee key is submitted to fetch colleagues list.

You can go through the slides from my AMIS25 session - Oracle JET CRUD and ADF BC REST. I explain similar concepts:


Download sample application (you must run ADF BC REST application in JDEV 12.2.1 and JET in NetBeans 8) - JETCRUDApp_v9.zip.

1. Filter implementation

We should take a look first, how filter/search functionality is implemented. User enters keyword for Last Name and filters data in JET table:


User can reset search results, change filter criteria. Filtering is done using startswith operator, by ADF BC VO (it creates temporary bind variable from REST URL parameter q=LastName LIKE value):


Filter block is implemented in a separate HTML div. Filter value is mapped with observable variable registered in JET View Model:


Table collection is based on collection with dynamic REST URL. URL is calculated through customURL property (referencing JavaScript method) in the collection. On filter event, we clear up all dependent data and call JET collection API method - refresh(). This ensures reload for collection and REST URL re-calculation. Similar is done on reset:


Method getURL is responsible to read filter value and construct REST URL accordingly (this will be used to re-fetch collection content):


Here you can see generated REST request URL logged by NetBeans Network Monitor. This URL contains filter information supplied through dynamic REST URL defined for the collection:


2. LOV data fetch implementation

There is LOV in ADF BC, which returns current employee colleagues (employees from the same job, except employee himself). ADF BC REST encapsulates parameters complexity and allows to simplify REST request. JET UI renders LOV data in a chart:


Each time when employee record is selected, we execute dynamic REST call (with new employee ID) to fetch colleagues collection:


This is chart definition in JET UI, it references observable variables for series/groups from JET View Model:


Similar as in the case with Filter, we supply dynamic URL for the collection, using property customURL:


Differently than in the Filter implementation, here we dont refresh collection. We execute JET API method fetch(...), to retrieve new collection and we push contents into observable variables, referenced by chart component in the UI: