Browsing "Older Posts"

Browsing Category "APEX examples"

Interactive Grid - Column stretching

Von Tobias Arnhold → 12.19.2018
Since APEX 18.1 you can define the stretch behavior per column.

You can choose between 3 different options:

Use Report Setting
The column will use the Stretch Report Setting set by the End User to define if the column should stretch or not.
In APEX 18.1 you have a new option to let the end user decide if the columns should be stretched or not.
This option effects all columns by default.

Never
The column will not stretch and always just use the width specified. This is useful for columns with short content like Yes/No or Numbers.
This option will over rule "Use Report Setting" and is really good for link columns or as the documentation says: short content columns.

Always
The column will always stretch, irrespective of the Stretch Report Setting set by the End User.


Results can look slightly different:


Imho: Small enhancement with huge impact.

APEX client side error messages - apex.message.showErrors

Von Tobias Arnhold → 10.25.2018
Since APEX 5.1 we have the ability to create client side messages without the requirement to use a plugin or custom code to create nice looking client side messages.

For that requirement the APEX team created the apex.message library.

This library provides the same look and feel as if you would create a message out of your Page Designer > Validation Area.



In this example I will tell you something about a more advanced way to use the client side error messages.

As the documentation says this is the default way to create a client side error message:

/* General page error message */
apex.message.showErrors([
{
type: "error",
location: "page",
message: "Page error has occurred!",
unsafe: false
}
]);
  /* Item error message */ apex.message.showErrors([
{
type: "error",
location: [ "page", "inline" ],
pageItem: "P1_ITEM",
message: "Value is required!",
unsafe: false
}
]);

Example for a page error message:




In my example I want to check more then one item. For that I created an array including all item names I wanted to check. Within a "FOR" loop I run through every item and created an error message if the value was NULL. If no error occurred I run another custom dynamic action.

apex.message.clearErrors();

var chkErr = 0;
var arr = [
   'P1_STRASSE', 
   'P1_HAUS_NR',
   'P1_PLZ', 
   'P1_ORT', 
   'P1_ITEM_XYZ'
];

for (var i in arr) {
  if ($v(arr[i]).length == 0) {
    apex.message.showErrors([
      {
        type: apex.message.TYPE.ERROR,
        location: ["inline"],
        pageItem: arr[i],
        message: "Value is required!",
        unsafe: false
      }
    ]);
    chkErr = 1;
  } 
}

if ( chkErr == 0 ) { 
  /* Custom dynamic action call when no error occurred */
  apex.event.trigger(document, 'customDA', [{customAttribute:'1'}]); 
}
You want to know more? Check out the documentation and this series of blog posts by Martin D'Souza:
https://www.talkapex.com/2018/03/custom-apex-notification-messages/
https://www.talkapex.com/2018/03/how-to-save-page-data-but-show-errors-in-apex/

#nextGENTrip18 a Twitter story

Von Tobias Arnhold → 8.27.2018
I would like to give you a feeling about our #NextGEN community activities by showing you a collection of tweets at the latest event which we participated:

The #ApexDay2018 in Stockholm at the SWEOUG

We have been 12 IT enthusiast from different places and different life circumstances.
 - 6 women and 6 men
 - 5 students and 5 employees and 2 freelancer
 - 9 Oracle specialists and 7 of them working primary with APEX


Goal

Get everyone further engaged in #NextGEN activities and inspire new IT enthusiasts to join our community/activities/events.

Follow DOAG #NextGEN

Website: https://www.doag.org/de/nextgen/nextgen/
Twitter: https://twitter.com/doagnextgen
Instagram: https://www.instagram.com/doagnextgen

The Twitter story




























5 reasons why 








You came this far... That can only mean that you want to join us.
We have a Slack channel where we organize new events and help each other on different topics. Especially APEX newcomer get a lot of support. Slack channel communication is in German. If you want to join then just write us an email: nextgen@doag.org


Set APEX application name for Dev, Test and Prod environment in the same database

Von Tobias Arnhold → 7.18.2018
In case you have a small application where development, test and maybe also production environment are on the same database and your applications in this environment distinguish only by the application IDs. To setup a custom application name based on the ID you could do like this:


We assume our application name is "Training room app" defined in the "Shared Components" > "User Interface Attributes"


To differentiate the environments I add a dynamic action "Page Load" on Page 0.
This dynamic action is executing custom Javascript code:

if ('&APP_ID.' == '200') {
  $('.t-Header-logo').find('span').html('Training room app - <b style="color:#008A34">Test Environment</b>');
}
else if ('&APP_ID.' == '300') {
  $('.t-Header-logo').find('span').html('Training room app - <b style="color:#9366a5">Development Environment</b>');
}


The code is changing the name of the logo area.

 

Copy and Paste to clipboard

Von Tobias Arnhold → 7.17.2018
Well I had the requirement to copy the content of a textarea into the clipboard. There are two ways to do that:

1. Build a dynamic action with custom Javascript code:
Copy Text to Clipboard

Code example - with dynamic action on "Click" and "Execute Javascript Code":
/* Select the text field */
$('#P1_APEX_ITEM').select();

/* Copy the text inside the text field */
document.execCommand("copy");



2. Use an APEX plugin:
Copy to Clipboard (v1.1) - build by Dick Dral



Icons made by Vitaly Gorbachev from www.flaticon.com is licensed by CC 3.0 BY

Enable save button on form change

Von Tobias Arnhold → 6.28.2018
Today I had the requirement that the save button should stay disabled until a form item changed.

After digging around I found a quite easy solution which worked well until now.

Save Button
Static ID: saveBtn
Custom Attributes: disabled

Dynamic Action
Event: Page Load
Execute Javascript Code:
$('#wwvFlowForm').on('input change', function() {
    $('#saveBtn').attr('disabled', false);
});



Simple but effective.

Working with the APEX tree

Von Tobias Arnhold → 6.27.2018
Out of a coincidence I haven't used the APEX tree region for years. Now I got the task to create a customizable tree in my application. Since APEX 5 there is a new tree type called "APEX tree" which supports some really cool functions.

Anyway I had to look around to find out what the APEX tree is actually capable of. First of all start with the APEX "Sample Trees" application which you find in the packaged application area.



Morten Braten took that example and described the features really well:
https://ora-00001.blogspot.com/2016/01/working-with-the-apex-5-treeview.html

John Snyders from the APEX team also created 2 blogposts about the "APEX tree":
APEX 5.0 Converting to the new APEX Tree
Add Checkbox Selection to APEX Tree Region

And as he mentioned there is a Javascript library behind it "libraries/apex/widget.treeView.js." which is documented since APEX 18.1 or at least I think it is. Anyway here is a link which I also have to further investigate:
JS Doc: Widget: treeView

German users can read this document provided by MT AG:
http://files.xmasman.de/20160216_MeetupNRW_TillAlbert_WiePflanzeIchEinenBaumApex.pdf

Check inside your APEX application if debug mode is enabled

Von Tobias Arnhold → 6.08.2018
Sounds like a simple task but whenever I have the requirement to add a region and make it conditional to check if APEX is running in debug mode. I always search for half an hour finding the right solution.

Search example on Google: "Oracle APEX check debug mode conditional PL/SQL"
Trying this or 30 different other ways it always ends up with the wrong results.

But it is so easy - Conditional PL/SQL Expression:
APEX_APPLICATION.G_DEBUG

G_DEBUG returns true or false!
The documentation is a bit imprecise because it says 'Yes' or 'No'.

Anyway it is all well documented in the APEX documentation
> APEX_APPLICATION > Global Variables:
https://docs.oracle.com/database/apex-18.1/AEAPI/Global-Variables.htm#AEAPI29544




CREATE or COPY master data pages in APEX

Von Tobias Arnhold → 3.07.2018
In this blog post I just want to give a hint about the positive and negatives effects when you COPY master data pages for different master data tables.

Example:
You have two tables: DOCUMENT_CATEGORY and ORDER_CATEGORY
Both tables have the same columns :
ID, CATEGORY_NAME, DESCRIPTION
CREATED_ON, CREATED_BY, CHANGED_ON, CHANGED_BY

In APEX you have a Master - Detail view including 2 pages: report view and modal dialog


If you decide to copy both pages you have to adjust the following things:
Master Data Report:
 - Page Name
 - Breadcrumb
 - Navigation Menu
 - Report DDL: Table Name
 - Report Column Link
 - Create Button Link

Modal Dialog:
 - After Header - Automatic Row Fetch (Name, Table Name)
 - Processing - Automatic Row Processing (Name, Table Name)
 - After Processing - Branch
 - APEX Items (in case you have different names or use prefixes)

What is the advantage?
1. Security
Security settings get copied like "Page Authorization Scheme". Master data pages normally apply to only one role, for example: administration
2. Labels and messages get copied (items, buttons). Really helpful if you named them differently to the standard APEX naming.

What is the disadvantage?
1. Linking
If you forget to change the branches/links then you could end up on the wrong page changing the wrong data. But on the other side this is the first thing you check after you finished the editing of the pages.
2. Automatic processing
If you forget to update the table names then you end up changing the wrong data.

Conclusion:
It is a bit more risky to copy master data pages but it can save you a lot of time changing label names and to remember the security settings.

Interactive Report - Column background color

Von Tobias Arnhold → 3.01.2018
One of my customers needed an IR where half of the report columns should be visualized in another color.


It is really easy to integrate. Go into the report column attributes inside your "Page Designer" and add a "Static ID" for each column:

Column 1: rep_col_diffcolor_1
Column 2: rep_col_diffcolor_2
...


Now add this CSS snippet inside the page attributes:

.a-IRR-table tr td[headers*="rep_col_diffcolor_"]
{
    background-color: #99ccff;
}


The trick is to address every element by searching for the start part of the "Static ID" name.

After the party is before the party

Von Tobias Arnhold → 10.20.2017
Now two months after the #pougtrip everything went back to normal. Except the planning for the next events.

The DOAG #NextGEN is currently starting a "roadshow" at German universities.

Start is the 07.11.2017 at the Trier University of Applied Sciences. We will have 3 presentations covering different technologies: SQL, JS, JSON, SVG, PL/SQL, REST and APEX.
But see for yourself: Oracle Vorträge an der Hochschule Trier


As you can see the agenda is made with APEX :). Inspired by the #pougtrip we plan free beer for all students!

This is our first test run to find out what it takes to get as much students as possible to listen to Oracle related technologies.

From my perspective the question is: What can an Oracle expert contribute to young professionals?

For example: handling real life problems and sharing the experience while using modern technologies. But I think most important is devotion.
You get inspired by an expert mostly depending on how dedicated this person is delivering the information. This event gives us the chance to inspire young professionals to see Oracle in a new light. See the possibilities and feel the devotion by the people who are working with the technology.

BTW: This event wouldn't be possible without two dedicated students. Thanks Rebecca and Abby!

JET pie chart in APEX with absolute numbers as data labels

Von Tobias Arnhold → 5.02.2017
The new APEX pie charts only allows percent values as data labels. Luckily the APEX team added an great example in the "Sample Chart" application which shows how to add custom data labels including absolute values by adding custom JavaScript code.

For German applications I prefer to display 10k (10000) like this: 10.000.
Thanks to APEX and JET it is easy to implement.

function( options ){
    this.donutSliceLabel = function( dataContext ){
        var value_ger;
       
        value_ger = dataContext.value.toLocaleString('de-DE', {
                      minimumFractionDigits: 0
                    });
       
        return value_ger;
    } 
    options.dataLabel = donutSliceLabel;
    return options;
}



Info: Technical updates in the JavaScript area are not supported by APEX updates. For example: A future JET version could have some engine changes which will not accept my JS example anymore.


Interactive Report Download Button only for a certain Authorization Role

Von Tobias Arnhold → 4.27.2017
The Interactive Report has this great download feature where you can export everything you can see.
Anyway there are circumstances where the customer doesn't want that feature open for everyone.

In APEX you can only choose if you want the download button or not.
Even so APEX can't do it out of the box. There is a way to make your application able to do it.

Since APEX 5 you can't download when the "Download" is disabled. If you try an almost empty page occurs. Ok that means the "Download" functionality must be activated an I have to disable it manually.

You need to focus on three steps:
 1. Add an authorization scheme.
 2. Hide the download button in the front end. (Visualization)
 3. Disable the download functionality in the back end. (Security)

1. Add an authorization scheme
The authorization scheme will handle the rights that only the correct person is allowed to download from the Interactive Report.
I my case I call it "ROLE_DOWNLOAD" and it works like that:
Type: PL/SQL Function Returning Boolean 
Function Body: return security_pkg.has_role(:APP_USER,'ROLE_DOWNLOAD');
Validate: Once per session

2. Hide the download button
Add a static report id


Add a new "Dynamic Action" on "Click".
jQuery Selector: #STATIC_REPORT_ID_actions_button
Event Scope: Dynamic
Security > Authorization: {Not ROLE_DOWNLOAD}



Add some Javascript to remove the button:
$('#STATIC_REPORT_ID_actions_menu .icon-irr-download').parent().parent().parent().remove();

3. Disable the download functionality
When APEX is exporting something from an "Interactive Report" itjust does a simple redirect on the same page and adds a REQUEST for the specific download type. In my case it is the request "CSV" I want to block.

Add a "Branch" executed "Before Header":


And to disable the download I just redirect on the same page without any request. The trick is to add the right PL/SQL Condition. In this example check for the request and the authorization scheme.

Code:
:REQUEST = 'CSV' and APEX_UTIL.PUBLIC_CHECK_AUTHORIZATION('ROLE_DOWNLOAD') = false

 
In my mind this is simple and secure and shows how flexible APEX really is.

An introduction into the APEX 5.1 Layout View

Von Tobias Arnhold → 4.04.2017
Many of you are still using the old "Component View" but the "Page Designer" introduced in APEX 5 made the developer life much easier.

The top 5 most time saving abilities for me are:
 1. Easy access on all page elements (without any page refresh)
 2. Copy&Paste of items, regions, dynamic actions, ... 
 3. Drag&Drop moving of items and regions
 4. Multi edit of items
 5. Since APEX 5.1: The ability to customize your own personal Page Designer View

The functionality "Layout" introduced in APEX 5 was not in my focus and as I remember I had some issues with it. So I just ignored it.

In APEX 5.1 I started a rerun on it using the "Universal Theme" and I must say it is a real help when you create a complex form page with a lot of page items. It feels different in APEX 5.1 and works almost flawless.

To get in touch with it I prepared a little example for you to help understanding the feature and may get inspired to use it, too.
We start with a page including 16 page items which should be visualized on 3 rows. Some of them are conditional and they are from different types (Text Field, Radio Group, Select List, Textarea).

All items are now displayed one below the other.


What do I aim for in the first step?
1. All items should have the label set to be "above". (Do not use the region template option for that)
2. I want to edit 8 page items split on two rows
3. Items 1-3 per row should be displayed over 2 columns
4. Item size must be adjusted



In between I made a Dynamic Action to make the "detail group" item conditional based on "Organization" if it is null or not.

I did the same for the category selector but I needed some Javascript code to make it right.


Code:
apex.item( "P9_CAT1_NAME_A" ).hide();
apex.item( "P9_CAT1_NAME_B" ).hide();
apex.item( "P9_CAT2_NAME" ).hide();
apex.item( "P9_CAT3_NAME" ).hide();
apex.item( "P9_CAT4_NAME_V1" ).hide(); 
apex.item( "P9_CAT4_NAME_V2" ).hide(); 
apex.item( "P9_CAT4_NAME_V3" ).hide();    

if ( $v("P9_CATEGORY_SELECTOR") == '1' ) {
    apex.item( "P9_CAT1_NAME_A" ).show();
    apex.item( "P9_CAT1_NAME_B" ).show();     
}
if ( $v("P9_CATEGORY_SELECTOR") == '2' ) {
    apex.item( "P9_CAT2_NAME" ).show();  
}

if ( $v("P9_CATEGORY_SELECTOR") == '3' ) {
    apex.item( "P9_CAT3_NAME" ).show();  
}
if ( $v("P9_CATEGORY_SELECTOR") == '4' ) {
    apex.item( "P9_CAT4_NAME_V1" ).show();
    apex.item( "P9_CAT4_NAME_V2" ).show();   
    apex.item( "P9_CAT4_NAME_V3" ).show();       
}

In my final move I finished the page by adjusting the other items.


The page looked like that:


But as always it could be a little bit better and luckily I used APEX. I just had to make a little change on it:

That's it. Hope you will give the "Layout"-View a chance to proof itself. :)


Info:
In case your Page Designer mentions problems in applying some multi update settings. Just refresh the page and try again.

Customize your Interactive Report with CSS

Von Tobias Arnhold → 3.28.2017
A lot of you are using jQuery to customize visual parts of an APEX application. I probably to often do so myself but there is a much more elegant way:   CSS

Nowadays you are able to add different kind of rules into your CSS styles. In this example I will show you how to get into the topic by changing an Interactive Report (IR). In my example I want to change the typical group by visualization.


Before


After


First of all you need to give your IR a unique name or class to identify it properly.
IR > Appearance > CSS Classes: irCustomStyles



Now you need to add the customized CSS code in your page:
Page > CSS > Inline

.irCustomStyles .a-IRR-table td {
    border-top: 0 solid #ffffff !important;
}

.irCustomStyles table.a-IRR-table th:first-child.a-IRR-header:not(.a-IRR-header--group) {
  background-color: white !important;
}

.irCustomStyles table.a-IRR-table tr:has( .a-IRR-header ) {
    border-bottom: medium none white !important;
    border-top: medium none white !important;
}

1. Rule: Takes the border from the TD elements away. Standard CSS probably most of you have done like this before. 
2. Rule: This one changes only the first TH element and when they are not referenced with class ".a-IRR-header--group"
3. Rule: The "has"-clause only applies if the result is true. In this case if a class called "a-IRR-header" exists.

Fore more details check those sources:
:not(s) - By Sara Cope
Selecting Parent Elements with CSS and jQuery - by Thoriq Firdaus

Run dynamic action from report row and pass multiple variables

Von Tobias Arnhold → 2.23.2017
Execute a "Dynamic Action" by clicking on a button/link inside a report row is mostly handled by some triggering HTML class.


It actually works in 95% of all cases. But it is not the best way to do it. It is much more effective to execute the "Dynamic Action" with a custom event.

Reason is simple: You don't need to allocate unnecessary elements via a class by jQuery. You execute the "Dynamic Action" in the moment when it is needed. Like calling explicitly a Javascript function.
This matters if you show maybe 500 rows or more on a single page or you handle several dynamic actions in one report.

Running a dynamic action from inside a report is actually an old hat because there are a few guys which have been written about it. Anyway I'm still searching for it every time I need it and some of the code pieces are not up to date anymore. So I will show you the way I handle it today and probably tomorrow, too. :)

First I must thank Jeff Eberhard for his examples about this topic. He really inspired me using the technique in one of my projects where I had to suffer with many rows inside a report.

Blog posts (www.eberapp.com/ords/f?p=BLOG):
Run Dynamic Action from JavaScript
Execute Dynamic Action From Report Column Link
Pass Multiple Values from Report to Dynamic Action

I prefer this way:

1. Set up a "Dynamic Action":
Custom Event: setIemsFromReport
Selection Type: Javascript Expression
Javascript Expression: document



1.1 Now add some action from type: "Execute Javascript Code"
In my example I set up three APEX items with data from my report row.

Code:
apex.item( "P1_DEVICE" ).setValue( this.data.device_name );
apex.item( "P1_IP" ).setValue( this.data.ip );
apex.item( "P1_KOST" ).setValue( this.data.kost );


Info:
As you see the parameters are forwarded with specific variable names. The example came from Matt Nolan. I prefer it mostly because it is exact and it makes it easier to understand (maintainability).

1.2 To get the values into your APEX database session you add one more action from type: "Execute PL/SQL Code":



2. Report column
Inside my report I define a link column which looks like that:

Type:
Link

Target:
javascript:apex.event.trigger(document, 'setIemsFromReport', [{device_name:'#NAME#', ip:'#IP#', kost:'#KOST#'}]);void(0);

Info
apex.event.trigger executes the "Dynamic Action". 
[{...}] defines the variables to forward.
void(0) prevents the browser to do further actions.

Link Text:
<span class="fa fa-edit"></span> 

Link Attributes (not required):
style="font-size:16px;color:#ICON_COLOR#;display:#ICON_DISPLAY#"

Info:
By using some columns with case when clause I'm able to add some custom attributes like hide/show. Example:
  case
    when SUBSTR(DEVICE,1,1) = 'T'
    then 'inline-block'
    else 'none' 
  end as ICON_DISPLAY


That is all you need to hand over attributes from your report row towards one or more APEX items on your page.

Using APEX_ERROR to manage custom error messages

Von Tobias Arnhold → 1.18.2017
Sometimes you just feel like you would be a newbie in coding business applications. Luckily it doesn't happen so often anymore. But this time it hit me hard. :)

During an application upgrade on Universal Theme I discovered an ugly workaround to create custom error messages I used in that time.

The old code looked like that:
declare 
  retval number;
  p_cust_id number;
  p_status varchar2(30);
  p_upduser varchar2(10);

begin 
  p_cust_id := :p1_cust_id;
  p_status  := 0;
  p_upduser := :app_user;

  retval := cust_apex_pkg.cust_apex_fnc ( p_cust_id, p_status, p_upduser );

  if retval = 1 then
    apex_application.g_print_success_message := '<span style="color: green;">Order was successfully published.</span>';
  elsif retval = 2 then
    apex_application.g_print_success_message := '<span style="color: red;">Error: Custom error 1 occurred.</span>';  
  elsif retval = 3 then
    apex_application.g_print_success_message := '<span style="color: red;">Error: Custom error 2 occurred.</span>';  
  else
    apex_application.g_print_success_message := '<span style="color: red;">Error: Unknown error occurred.</span>';  
  end if;
  commit; 
end;
As you can see I used the apex_application.g_print_success_message to overwrite the text color. Quite ugly but it worked as expected.
Anyway on Universal Theme it looked not so nice anymore because a "success message" has always a green background color. Putting some red text color above is not the user experience I would prefer.


I searched for about 3 minutes and found a really good article from Jorge Rimblas writing about the APEX_ERROR package. The blog post is from 2013 so this procedure must be available for a while now. What made me feeling like a jerk. The good side is that I now can start again to climb up on the iron throne. :)

The updated code looked like that:

declare 
  retval number;
  p_cust_id number;
  p_status varchar2(30);
  p_upduser varchar2(10);

begin 
  p_cust_id := :p1_cust_id;
  p_status  := 0;
  p_upduser := :app_user;

  retval := cust_apex_pkg.cust_apex_fnc ( p_cust_id, p_status, p_upduser );

  if retval = 1 then
    apex_application.g_print_success_message := 'Order was successfully published.';
  elsif retval = 2 then
    apex_error.add_error(
      p_message => 'Error: Custom error 1 occurred.'
    , p_display_location => apex_error.c_inline_in_notification
    );
  elsif retval = 3 then
    apex_error.add_error(
      p_message => 'Error: Custom error 2 occurred.'
    , p_display_location => apex_error.c_inline_in_notification
    );
  else
    apex_error.add_error(
      p_message => 'Error: Unknown error occurred.'
    , p_display_location => apex_error.c_inline_in_notification
    );
  end if;

  commit; 
end;

Thanks Jorges by blogging and sharing your knowledge.

APEX IR column only exportable for administrators

Von Tobias Arnhold → 1.13.2017
A few days ago I tweeted about a solution from Martin Giffy D'Souza to hide a specific column from export.


In my case I needed some username columns to be displayed during run-time but only exportable for administrators. The export itself was made with the default APEX CSV export.


Martin solutions was a really good starting point. I just had to add some security checks for the administrator role. And all together was put into a new authorization scheme which I added inside the conditional columns of my Interactive Report.

-- Authorization Scheme Name: ROLE_EXPORT_USERNAME
-- Validate authorization scheme: Once per page view

-- Code:
if pkg_security.has_user_role(:APP_USER,'ADMIN') = true or :REQUEST != 'CSV' then
  return true;
else
  return false;
end if;