Monday, February 14, 2022

Javascript API (#4 Message namespace)

Hello everyone and welcome again here in our Blog. In this post, we will show you how to use the message namespace, and as always, with a practical example.

The message namespace is one of the native apex namespaces provided to you. This namespace is used to handle client-side display and management of messages, such as error and success messages. 

When to use the message namespace?

you use this namespace when you want to show some messages to the users. A very common use-case is validation, for example, you have a required text field and you want to alert the user if he leaves it empty, or if the text field must be in Email format. You can also use the namespace to show a success message after a user successfully complete a process. These are some use-cases where you can benefit from the message namespace.

Message types

The namespace has two message types, ERROR, and SUCCESS. You can use the property TYPE to specify the type of message you want as we will see later in this post. 

Functions

The namespace provides some functions that you can use to perform some tasks. Below we will take a look at some of these functions.

alert()

The first function we will talk about is alert(), which is used to display the alert dialog with a message passed as a parameter and an Ok button, you can also provide a callback function that will be fired after the user responds to this alert. The dialog displays using the jQuery UI ‘Dialog’ widget and there are some differences between this function and a browser’s built-in alert function:
  • The dialog style is consistent with the rest of the app.
  • The dialog can be moved.
  • The call to apex.message.alert does not block. Any code defined following the call to apex.message.alert will run before the user presses OK. Therefore code to run after the user closes the dialog must be done from within the callback.
Now let's have an example, go to our Demo app or create a new application if you don't already have one, navigate to the first page and create a new region with a button and let's name the button "show alert", now add a dynamic action to that button and set the true action to Javascript (please note that there is already an alert action provided to you, but in this series, we are the Javascript APIs) add the following code and run the application
apex.message.alert("some alert text", ()=>{
console.log("This runs after the dialog is closed");
});
Once the user clicks the show alert button, the dialog shows up with the message and an ok button. The user has to press the ok button to close the dialog, once he has done that, the callback function will be executed.

confirm()

Similar to the alert function, but here, the dialog has a cancel button beside the ok button. In this function, the callback function accepts a parameter that tells you whether the user pressed the Ok button or the cancel button, so you can perform different actions depending on the user input. This is useful when you want to warn the user before deleting something for example. 
Go back to the demo app, add a new button "Show Confirm", add a dynamic action to the button and add a true action that runs the following code
apex.message.confirm("some text", (okPressed)=>{
if (okPressed)
console.log("The user pressed the ok Button");
else
console.log("The user pressed the Cancel Button");
});
Run the application and open the console to see the output. 

showPageSuccess()

You can use this function to show the user a success message with a specific message, for example, when a user successfully filled out a form or to show that a transaction was successfully saved. 
Go to the demo app, add a new button "ShowSuccessMessage", add a dynamic action and change the true action to execute Javascript code then add the following code
apex.message.showPageSuccess( "Changes saved!" );
Run the application and try it! 

hidePageSuccess()

As the name suggests, this function hides the page success notification. After you display a success message, it won't disappear until you hide it, one way to do that is using this function. 
Go back to the previously created dynamic action that shows the success message and change the code to the following
apex.message.showPageSuccess( "Changes saved!" );
setTimeout(()=>{
apex.message.hidePageSuccess();
}, 1000);
This will set a timeout and the hide-message will be executed 1 second after it is displayed.

clearErrors()

This function clears any errors currently displayed on the page, we will use this function later in this post when we talk about showErrors() function

showErrors()

This function is used to display error messages to the user, when they enter a wrong value in an input text item or when something went wrong while saving a form. You can show the error message on a page level which means all error messages will be shown on the right corner of the page and the style will be inherited from the page notification template, or you can show the error message next to the item where the error occurred, in this case, the style will be driven from the item label template.  You don't need to worry about the style and the markup, you just have to specify the location where the notification will be displayed. The function accepts an object or an array of objects, in each object you can specify the message attributes e.g. location, message text, and so on. 
Go to the demo app, add a text item, give it the name "P1_ERROR_MESSAGE" and a button "ShowError"
Then add a dynamic action to the button, change the true action to execute Javascript code, and write the following code
apex.message.clearErrors();
apex.message.showErrors([
{
type: "error",
location: [ "page", "inline" ],
pageItem: "P1_ERROR_MESSAGE",
message: "Name is required!",
unsafe: false
},
{
type: "error",
location: "page",
message: "Page error has occurred!",
unsafe: false
}
]);
The first line in the code clears the error stack, in case the user had previous errors and, the second line adds two errors to the error stack and shows them. 
The first error in the array is an object, the type of the notification is an error and in the location attribute we want to show the error message on the page level and also next to the item, so in the pageItem attribute we should tell which page item is associated with this error message, the next attribute is the message we want to show and finally, the last attribute tells the function whether to escape the message text or not, in this case, the message text is considered as a safe message so it won't be escaped. 
the next error object is a page-level error and therefore we don't need to specify a page item. 
Run the application and you should see something like this

setThemeHooks()

If you want to change the default behavior of the notification messages or if you want to override the style then you need to use this function. It allows you to run a specific code before the show page notification functionality, and also before the hiding page notification functionality. Let's say for example you want the success messages to disappear 3 seconds after displaying, but if the message type is an error then you don't want it to disappear automatically. 
Go to our page where all items are and in the "Execute when page loads" write the following code (It is better to add this code in template initialization code, but for this demo is ok)
apex.message.setThemeHooks({
beforeShow: function( pMsgType, pElement$ ){
if ( pMsgType === apex.message.TYPE.SUCCESS ) {
setTimeout(function() {
$('.t-Alert').fadeOut('slow');
}, 2000);
}
},
beforeHide: function( pMsgType, pElement$ ){
console.log("This is before hide!");
}
});
The pMsgType parameter identifies the message type (as we said before, there are two types Error and Success), and the pElement$ parameter is the JQuery object that contains the element to being shown (the notification element, in our case, would be an HTML span element).
Go to the show success dynamic action and comment the code that hides the success message
Run the application and try it (you need to open the console to see the beforeHide message). 

So that's it in this post, we hope that you learned something :).


References:
  • https://docs.oracle.com/en/database/oracle/application-express/21.2/aexjs/apex.message.html



Labels: , ,

Thursday, December 9, 2021

Javascript APIs (#3 the date namespace)

Hello everyone and welcome back to a new blog, this blog is one of the blog series about the Javascript APIs that we have started. In this blog, we will talk about the date namespace so let's get started :). 

The apex.date namespace contains the oracle APEX functions related to date operations, so this API has functions that will help you work with the date items and values. It makes working with different dates format much easier than using normal Javascript. 

Before we start, go to our demo app, navigate to the first page and add a new static region. Now we can start...

date.parse()

this function returns parsed date object of a given date string and a format mask, it accepts a date in a string format and converts it into a date object so you can use all methods available on a date object. The function uses the default date format mask defined in the application globalization settings. 
Go to the demo app and add the following in the new static region
  • Date page item: name= P1_DATE1
  • Display only page item: name=P1_DATE1_VAL
  • Dynamic action that fires when P1_DATE1 changes: add a new true action that run the following Javascript code:
                                            let date_val = apex.item('P1_DATE1').getValue();
                                            let parsed_date = apex.date.parse(date_val);
                                            apex.items.P1_DATE1_VAL.value=parsed_date.toString();
you should have something like 

in the code above, we converted the value of the date object into a string to show it in the display-only item. the parse() function accepts a second parameter to specify the format, if the parameter is not given, the function uses the default format and language defined in the application globalization settings. To check your application setting, you can go to shared components and see globalization, or open the developer tool in your browser and write the following javascript code:
apex.local.getDateFormat();
apex.local.getLanguage();
you can also try using a different format, type the following in you console
apex.date.parse('2021.12.02 11:20','YYYY.MM.DD HH24:MI')

date.add() 

This function is used to add a certain amount of time to an existing date object, it also returns a date object. the function accepts three parameters, the first is the date object you want to modify, the second is the amount you want to add, and the third is optional which is the unit.
Go back to the Demo app and add the following:
  • Date page item: name= P1_DATE2
  • button: name= addDay
  • dynamic action fires when addDay button click: add a true action that execute the following Javascript code
let strDate = apex.items.P1_DATE2.value;
let dateVal = apex.date.parse(strDate);
let newDate = apex.date.add(dateVal, 1, apex.date.UNIT.DAY);
apex.items.P1_DATE2.value = newDate.toString();
in the same way, you can add a Month, year, or any amount of time. Just change the unit. You can also subtract a specific amount of date from a date object using subtract()

date.format()

you can use this function to change the default date format, meaning if you want to use a specific date format other than the default one. but keep in mind that you can only use oracle compatible format masks. by giving an extra parameter you can also specify the language you want.
Add the following items in the demo app
  • Date page item: name= P1_FORMAT
  • Display only page item: name=P1_FORMAT_VAL
  • Button: name=format
  • Dynamic action fires when the format button is clicked, add a true action which runs the following Javascript code:
let strDate = apex.items.P1_FOMRAT.value;
let selectedDate = apex.date.parse(strDate);
let formattedDate = apex.date.format(selectedDate, 'yyyy.Month.dd', 'de');

apex.items.P1_FORMAT_VAL.value = formatted date;

date.firstOfMonth()

this function is very useful, it returns a date object for the first day a month of a given date object. You have a date object and you want to get the first day in the month of your date, just use this function.
Add the follwoing in the demo app
  • Date page item: name=P1_DATE3
  • Display only page item: name= P1_FIRST_DAY
  • Button: name= getFirstDay
  • Dynamic action fires when getFirstDay button click: add a new true action which runs the following Javascript code
let strDate = apex.items.P1_DATE3.value;
let selectedDate = apex.date.parse(strDate);
let firstDay = apex.date.firstOfMonth(selectedDate);

apex.items.P1_FIRST_DAY.value = apex.date.format(firstDay,'yyyy.mm.dd');
you should have something like this:

there is a similar function to get the last of the month, just use lastOfMonth() instead of firstOfMonth()

isAfter()

this function is used to compare two date objects, it returns true if the first date object is after the second date object, otherwise, it returns false.
Add the following items to the demo app
  • 2x Date page item: name= P1_FIRST_DATE, P1_SECOND_DATE
  • Display only page item: name= P1_RESULT
  • Button: name=compare
  • Dynamic action fires when compare button is clicked: add a true action that runs the following Javascript code
let strFirstDate = apex.items.P1_FIRST_DATE.value;
let strSecondDate = apex.items.P1_SECOND_DATE.value;

let firstDate = apex.date.parse(strFirstDate);
let secondDate = apex.date.parse(strSecondDate);

let result = apex.date.isAfter(firstDate, secondDate);

apex.items.P1_RESULT.value = result;
in the same way, you can compare is a date object is before a given date, just use isBefore()

date.isSame()

this function is used for comparing two dates, it returns true if the first date matches the second.
Go to the demo app and add the following:
  • Date page item: name=P1_IS_SAME1
  • Date page item: name=P1_IS_SAME2
  • Display only page item: name = P1_IS_SAME_VAL
  • Button (name=P1_IS_SAME) with a dynamic action which fires on the button click and runs the following Javascript code:
let strDate1 = apex.items.P1_IS_SAME1.value;
let strDate2 = apex.items.P1_IS_SAME2.value;

let date1 = apex.date.parse(strDate1);
let date2 = apex.date.parse(strDate2);

let result = apex.date.isSame(date1,date2);

apex.items.P1_IS_SAME_VAL.value = result;

date.isLeapYear()

this will be the last function for this blog. As the name suggests, this function tells you whether the given year is a leap year or not, it returns true when it is. let's try it by adding the following to the demo app
  • Date page item: name= P1_LEAP
  • Display only page item: name= P1_LEAP_VAL
  • Button: name= P1_CHECK
  • Dynamic action fires when the button is clicked, add a true action that runs the following Javascript code
let strDate = apex.items.P1_LEAP.value;
let leapDate = apex.date.parse(strDate);

let isLeap = apex.date.isLeapYear(leapDate);

apex.items.P1_LEAP_VAL.value = isLeap;

So that's it for this post, in the next post we will start with a new namespace :).


References:
  • https://docs.oracle.com/en/database/oracle/application-express/21.2/aexjs/apex.date.html#.isLeapYear






Labels: , , ,

Thursday, December 2, 2021

Javascript APIs (#2 apex.item)

Hello everyone and welcome back to the next post where we will cover the second part of the item interface. This post is one of a series in which we will discuss the most commonly used Javascript APIs. 

In the following, we will continue by explaining the methods provided by the item interface and see how we can use them in our Demo app. 

Disable, Enable, and isDisabled methods

as the name suggests, these methods can be used to Disable or Enable one of the page items, they make it either available for editing or unavailable. Please notice, that not all items support being editable, so we can't use this method on all items. We can use them only on items that can be edited e.g text field items.
Go to the demo app we created in the last post and add the following item and dynamic actions in a new static region:
  • Text field page item: name=P1_ITEM3
  • Button: name=change
  • Dynamic action: fires when change button is clicked, add a true action that execute the following javascript code:

if (apex.items.P1_ITEM3.isDisabled())
    apex.items.P1_ITEM3.enable();
    else
    apex.items.P1_ITEM3.disable();

as you can see in the code we first test whether the text field is already disabled if this was the case, we enable it, otherwise, we disable it. 


run the application and test it, please note that you can achieve the same by simply using the predefined dynamic action which enables/disables an item. but the idea here is to learn how to use the JS API.

getValue/setValue methods

getValue returns the current value of an item. There is a shorthand for this function which is $v() and also as we discussed in the previous post you can use the value attribute of the item. e.g 
apex.items.P1_ITEM1.value
is equivalent to
apex.item('P1_ITEM1').getValue()
and are the same as
$v('P1_ITEM1')
Now, for setting an item value we can use the shorthand $s() or the item attribute value or we can use the  following function which give us more options
apex.item('P1_ITEM1').setValue(param1,param2,param3)
this function sets the current value of the item, but the session state will not be affected until you submit the page (or you can use AJAX) .
param1: the value to set. if the item can accept more than one value, you can give those values as an array of string
param2: the display value. This parameter is optional, you have to provide it when the display value is not the same as the item value.
param3: some items have a change event, this event will run the callback function whenever the item value has been changed. You can prevent the event from firing by giving true as a value for this parameter. 
Go back to our demo and add the following:
  • text field page item: name= P1_ITEM5
  • display only page item: name=P1_ITEM5_VAL
  • dynamic action that fires on key release: selection type=item, item=P1_ITEM5. this dynamic action has a true action which runs the following javascript: 
apex.item('P1_ITEM5_VAL').setValue(apex.item('P1_ITEM5').getValue())
run the application and test it. 

setStyle method

this method sets the style of an item, meaning you change the style of an item as you do use CSS. However, keep in mind that this method is not the best practice. It is also recommended that you add/remove the class of an item and then edit the style in your CSS code using those classes.
Go to the demo app and add the following 
  • text field page item: name=P1_ITEM6
  • button: name=change_color
  • dynamic action that fires on change_color click: add a true action which runs the following javascript code
apex.item( "P1_ITEM6" ).setStyle( "background", "red" );
so at the end your application should look something like

so as you see there are many ways to use these cool APIs... all other methods are basically the same, you know have an idea about how to use them... so go to the JS APIs documentation and have a look and stay tuned for our coming posts :)

Demo

References

  • https://docs.oracle.com/en/database/oracle/application-express/21.2/aexjs/item.html#setStyle




Labels: , , ,

Monday, November 29, 2021

Introduction Oracle APEX JavaScript APIs (#1 apex.item)


Hello everyone and welcome back to our Blog. In this blog series, we would like to draw your attention to some Javascript APIs provided by APEX. Those APIs will help you to write much efficient Javascript code and will make your life much easier :-).
In each post, we will take one of these APIs and demonstrate our understanding in a demo. Before we dive into the first API, let's first explain what is APEX Javascript APIs and how it works.

APEX provides some functions to make it easy for developers to interact with the items, regions, reports, and many other objects in a simpler way than using plain Javascript. You can use these functions to provide client-side functionality, such as showing and hiding page elements, or making Ajax (Asynchronous JavaScript and XML) requests.

Most of the APEX JavaScript APIs are organized into namespaces. There is one top-level APEX namespace called apex. This has a number of sub-namespaces such as apex.server and apex.util. Namespaces help to organize code and reduce the chance of name conflicts with other JavaScript libraries.

There are some older global functions that are not in a namespace. Most of them start with a $ character. These are known as Non-namespace APIs. Global symbols that begin with APEX or $ are reserved by APEX.

Some functions return an interface, which is an object that contains functions known as methods and variables known as properties, that allows access to a specific instance of a page component or other entity.

APEX also includes a number of UI widgets based on the jQuery UI widget factory. Widgets are high-level user interface components such as menus, trees, or grids. 

Now and after this introduction, let's start with the first API which is the item function. This function returns an item interface that is used to access item-related methods and properties. As of the latest APEX versions, when you call apex.item() you get back an item interface that is specific to the type of item it is. For example, the interface for a Number Field item had the extra method getNativeValue.


Let's create a demo app in apex.oracle.com and use various items to see some of the advantages of using this interface. Create a page and add a static region in it.

Please keep in mind that we are not going through all props and methods, we will just discuss the most useful ones.

Accessning Page Items

there are two ways to access one of your page items. The first option is to use the apex.item() function by providing the item name you want to access as a string, for example apex.item('P1_ITEM'). The second way is to use the apex.items module for example apex.items.P1_ITEM

Element Property

this property returns the JQuery object for the selected element, so it is equivalent to the JQuery selector using id $('#id'). 
In our demo app add the following items in the static region: 
  • Text Field item: name=P1_ITEM0
  • Display only item: name:P1_ITEM0_VAL
  • button: name:Get
add a dynamic action to the button which fire on button click and a true action which execute a javascript code and write the following code:
apex.items.P1_ITEM0_VAL.value=apex.items.P1_ITEM0.element[0].outerHTML
you should have something like this:


run the application, press the button and you should get the JQuery object of the text field element (which is P1_ITEM0) displayed in the display only element (P1_ITEM0_VAL).
In the Code you can see that we used one of the JQuery property to get the DOM element as text of the selected element, you use the node property which is provided by the item interface to get the DOM element directly e.g apex.items.P1_ITEM0.node

Value Property

in the previous example we used this property to set the value of the display only item, you can use the value property to get and set the page items value. In a future posts we will see that you can set/get items values using methods provided by the interface, however using the property is a shorthand of those methods.
for getting an item value, you can simply write:
apex.items.P1_ITEM1.value
or you can use
apex.item('P1_ITEM1').value

In the static region add the following items and dynamic action:
  • Text field item: name=P1_ITEM1
  • Display only item: name=P1_ITEM1_VAL
  • Dynamic action: event=Key Release, selection type=item, items=P1_ITEM1. add a true action that execute the following javascript code: apex.items.P1_ITEM1_VAL.setValue(apex.items.P1_ITEM1.value)
at the end you should have something like:


Now run the application and try to write something in the text field, you should see directly that what you are writing is being displayed on the other item (the display only item)

item_type property

this will give you back the item type, e.g date, number, text, etc. So if you want to know the type of your page item, you only have to write this line of code and you are done:
apex.item('P1_ITEM2').item_type

in the static region add the following page items and dynamic actions:
  • Date page item: name= P1_ITEM2
  • Display only page item: name=P1_ITEM2_VAL
  • dynamic action that fires on page load, and has a true action of type set value, type is javascript and write the following: apex.item('P1_ITEM2').item_type. make sure that the true action will fire on page initialization.

run the application and notice the result. 



in this post we have discussed the properties that are provided by the item interface and we gave some basic examples on how to use each of these props. In the next post we will discuss the most useful methods provided by the same interface, so stick around ;).


References:
  • https://docs.oracle.com/en/database/oracle/application-express/21.2/aexjs/item.html#item_type




Labels: , ,

Thursday, April 8, 2021

Two ways to fetch the current records (Interactive Grid #10)

 




Last but not least tip no. 10!


#10 Two ways to fetch the current records

This will be the last blog in the series for now, but no less interesting than the others :-)

In this entry, we want to show how you can fetch the records of an interactive grid in two different ways. 
The first method is using a JavaScript function, as the second method we employ a PL/SQL function. Both are easy to implement. You can determine your approach depending on what you want to do with the data. Personally, I prefer PL/SQL and avoid JavaScript code whenever it´s possible but every developer thinks differently here :-)

Let's have a closer look at how we can do this.


1) Fetch records via JavaScript 

We start with a new application or page where we will add an interactive grid. In our example we use the table "EMP" as source. Then we give the Interactive Grid a Static ID, for example "my_ig". In our case we only want to fetch the values of the "EMPNO" column and save them in a page item. This is a very basic example, but it suffices to show how it works. Next we need a page item that we call "P1_EMPNO_JS". When that is done, we add a Dynamic Action and set the following:
  • Event: 'Page change (Interactive Grid)'
  • Selection type: 'Region' 
  • Region: 'The Interactive Grid you add to the page'
The Dynamic Action is fired every time the selection of the Interactive Grid changes. We can also use a button or some other DA event. The final thing we need is a 'True' action that executes JavaScript Code. Here we enter the following JavaScript function:


var l_empno;
// fetch the model for the interactive grid
var model = apex.region("my_ig").widget().interactiveGrid("getViews", "grid").model;

// loop through the records
model.forEach(function(igrow) {
   if(l_empno == null){
       // first row without seperator ":"
       l_empno = igrow[model.getFieldKey("EMPNO")];
   }
   else {
       // add seperator ":" to each additional row
       l_empno = l_empno + ':' + igrow[model.getFieldKey("EMPNO")];
   }
}
);

// Set Page Item
apex.item( "P1_EMPNO_JS" ).setValue (l_empno);


What we are doing here is getting the model of the Interactive Grid, and looping through each row and writing the value of "EMPNO" to a variable. At the end we store the result of the variable in a page item.

That´s it ;-)


2) Fetch records via PL/SQL 

In our second example we use the same Interactive Grid as before. We need a second Page Item, which we call "P1_EMPNO_SQL", and another Dynamic Action, which, as in the previous example, is also fired on a "Page change (Interactive Grid)" event. For the DA we need a 'True' action that executes PL/SQL code and enter the following:


declare
    l_region_id number;
    l_context   apex_exec.t_context; 
    l_empno_ids number; 
    l_empno     varchar2(1000 CHAR);
begin
    -- Get the region id for the IG
    select region_id
      into l_region_id
      from apex_application_page_regions
     where application_id = :APP_ID
       and page_id        = :APP_PAGE_ID
       and static_id      = 'my_ig';

    -- Get the query context for the IG
    l_context := apex_region.open_query_context (
                        p_page_id => :APP_PAGE_ID,
                        p_region_id => l_region_id );

    -- Get the column positions for column(s)
    l_empno_ids := apex_exec.get_column_position( l_context, 'EMPNO' );

    -- Loop through the query of the context
    while apex_exec.next_row( l_context ) loop 
        if l_empno is null then
            -- first row without seperator ":"
            l_empno := apex_exec.get_number( l_context, l_empno_ids );
        else    
            -- add seperator ":" to each additional row
            l_empno := l_empno || ':' || apex_exec.get_number( l_context, l_empno_ids );
        end if;    
    end loop;
    
    -- Set Page Item
    :P1_EMPNO_SQL := l_empno;

    -- Close query context
    apex_exec.close( l_context );
exception
      when others then        
        apex_exec.close( l_context );
      raise;
end;      


What we're doing here is the same process as before in our JavaScript function. We get the query context of the Interactive Grid, loop through each row and write the value "EMPNO" to a variable. Some APEX APIs are used to achieve this, which will not be described in further detail here, but we are going to have a closer look at them in future blogs, so keep an eye out.


The examples here are very basic but show what can be achieved with a bit of customization. You can do a lot this way, for example fetching the records of the IG in order to insert or update data in this or another table. Using the JavaScript approach, it is possible to make your page more interactive, for example to show or hide regions/items/buttons based on the selected data. 


Feel free to let us know if these tips and tricks helped you. 
If you have questions or suggestions, please leave us a comment ;-)


Here is the demo app for reference.


References:
  • https://docs.oracle.com/en/database/oracle/application-express/20.2/aexjs/grid.html
  • https://docs.oracle.com/en/database/oracle/application-express/20.2/aeapi/APEX_REGION-OPEN_QUERY_CONTEXT-Function.html#GUID-BDB9F4B7-D1A7-4C9A-B4C7-45A57AD76427
  • https://docs.oracle.com/en/database/oracle/application-express/20.2/aeapi/APEX_EXEC.html#GUID-3CF1D2DD-AEA4-4982-9857-548567AB7169

Labels: , ,

Wednesday, March 17, 2021

Customize your Toolbar (Interactive Grid #9)

  







Next to last tip no.9!


#9 Customize your Toolbar

As the previous blog entries mentioned, the interactive grid brings many out-of-the-box features on the one hand, but also many adjustments that can be made on the other. This means it is possible for the developer to customize the toolbar the way the customer wants. This article shows some examples of how you can customize the interactive grid Toolbar without much effort.

Before we can start, however, we should understand how the toolbar is structured.




As you can see in the figure, the toolbar consists of seven different menu groups (arrays) that can all be customized individually. In our example we will first hide all menu groups and then only the "action1"  menu group will be customized and displayed.


Let's start with a new application or page where we will add an interactive grid. In our example we use the table "EMP" as source. The toolbar of the interactive grid can be customized via JavaScript. For this we have to add some JavaScript Initialization Code under the attributes of the IG. First we will hide the unneeded menu groups and locate the menu group "actions1" that we want to customize.


function(config) {
    var $ = apex.jQuery,
    toolbarData = $.apex.interactiveGrid.copyDefaultToolbar(),  // Make a copy of the default toolbar
    toolbarGroup = toolbarData.toolbarRemove("search");         // Remove the search menu group
    toolbarGroup = toolbarData.toolbarRemove("reports");        // Remove the reports menu group
    toolbarGroup = toolbarData.toolbarRemove("views");          // Remove the views menu group
    toolbarGroup = toolbarData.toolbarRemove("actions2");       // Remove the actions2 menu group
    toolbarGroup = toolbarData.toolbarRemove("actions3");       // Remove the actions3 menu group
    toolbarGroup = toolbarData.toolbarRemove("actions4");       // Remove the actions4 menu group
    toolbarGroup = toolbarData.toolbarFind("actions1");         // Locate the actions menu group  
    
    // Add new control elements here

    // Assign new toolbar data back to toolbarData configuration property
    config.toolbarData = toolbarData;

    // Return the config
    return config;
}


After we have done that and started the application, we see that we have created an IG with a blank toolbar. The next step is to add some elements to the toolbar.

The most common element is probably the button. Let's add some button to the toolbar first. 
The structure is always the same. We declare a type, label, icon and an action to be executed.


    // Add new buttons
    // Note the toolbar is action driven, so we just need to define the correct action name with the button.
    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "Add Row(s)",
        action: "selection-add-row",
        icon: "icon-ig-add-row",
        iconBeforeLabel: true,
        hot: true
    });    
    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "Delete Row(s)",
        action: "selection-delete",
        icon: "icon-ig-delete",
        iconBeforeLabel: true,
        hot: true
    });
    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "Save",
        action: "save",
        icon: "icon-ig-save",
        iconBeforeLabel: true,
        hot: true
    });


There are many default widgets for the interactive grid that we can use. For a complete reference, see the list below.




In our case we use the "Add Row", "Delete Row" and "Save Changes" action as an example, but we can also define and execute our own custom actions or trigger Dynamic Actions or an AJAX process. The next code snippet shows you how you can directly execute a JS command or trigger a Dynamic Action.  Note that you have to create the custom Dynamic Action, too.


    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "My Button",
        icon: "fa fa-american-sign-language-interpreting",
        iconBeforeLabel: true,
        hot: true,
        action: "my_action"
    });
    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "My DA Button",
        icon: "fa fa-play",
        iconBeforeLabel: true,
        hot: true,
        action: "my_da"
    });  
    
    config.initActions = function(actions){
        actions.add({
            name: "my_action",
            action: function() {
            alert('Hello World');
            }
        });
        
        actions.add({
            name: "my_da",
            action: function() {
            $.event.trigger('my_da');
            }
        });
    }


Now our toolbar should look like this.




Our next step in customizing the toolbar will be to add a select-list. To do this, we follow the same procedure as before and add another control element which is of type "SELECT". 


    // Add new select-list    
    toolbarGroup.controls.push({
        type: "SELECT",
        title: "Select",
        id: "my_select",
        action: "my_select_action"
    });    


Again, we need to also create a custom action to add values to the Select List and an event to be triggered.


    actions.add({
        name: "my_select_action",
        choices: [{ label: "All Jobs", value: "" },
                  { label: "President", value: "PRESIDE" }, 
                  { label: "Manager", value: "MANAGER" },
                  { label: "Analyst", value: "ANALYST" },
                  { label: "Clerk", value: "CLERK" },
                  { label: "Salesman", value: "SALESMAN" }                  
                 ],
        action: function(event, focusElement) {
        var e = document.getElementById("my_ig_ig_toolbar_my_select"),
            value = e.options[e.selectedIndex].value;
            apex.item( "P1_JOB" ).setValue(value);
        }
    });


Here we create a list of the jobs and save the value in an item (P1_JOB). Now we can work with this value and, for example, filter our interactive grid. 
For this we create a hidden item which we also call "P1_JOB" and also a new "Change" Dynamic Action for that item. After that, we add a "True" action to refresh the grid. Finally adjust the WHERE clause of the grid and pick P1_JOB to "Page Items to Submit"




Now our toolbar should look like this and we can filter our IG by selecting a value from the Select List.




Finally we are going tol add a menu to the toolbar.

For this, we need a new control element of type "MENU". That is the easy part because we already know how to do it. However, defining the menu items is a little bit harder. Each entry has its own type, action, label and other options that we can define. Note: each additional entry needs a separator first.
In our example, we'll use the "Highlight" and "Download" pre-defined action, plus two other custom actions that will trigger an alert.


    // Add a Menu to the toolbar
    toolbarGroup.controls.push({type: "MENU",
        id: "my-menu",
        label: "My Menu",
        icon: "fa fa-navicon",
        iconBeforeLabel: true,
        hot: false,
        action: "custom-menu",
        // Add Menu Items (each additional entry needs a separator)
        menu: {
            items: [{
                type: "action",
                action: "show-highlight-dialog",
                label: "Highlight"
            }, {
                type: "separator"
            }, {
                type: "action",
                action: "show-download-dialog",
                label: "Download"
            }, {
                type: "separator"
            }, {
                type: "action",
                action: function(){ alert('Action 1');},
                label: "Action 1",
                icon: "fa fa-number-1-o"
            }, {
                type: "separator"
            }, {
                type: "action",                
                label: "Action 2",
                action: function(){ alert('Action 2');},
                icon: "fa fa-number-2-o"
            }]
        }
    });


So thats it. Your toolbar should now look like this.



The finished JavaScript Code should be the following:


function(config) {
    var $ = apex.jQuery,
    toolbarData = $.apex.interactiveGrid.copyDefaultToolbar(),  // Make a copy of the default toolbar
    toolbarGroup = toolbarData.toolbarRemove("search");         // Remove the search menu group
    toolbarGroup = toolbarData.toolbarRemove("reports");        // Remove the reports menu group
    toolbarGroup = toolbarData.toolbarRemove("views");          // Remove the views menu group
    toolbarGroup = toolbarData.toolbarRemove("actions2");       // Remove the actions2 menu group
    toolbarGroup = toolbarData.toolbarRemove("actions3");       // Remove the actions3 menu group
    toolbarGroup = toolbarData.toolbarRemove("actions4");       // Remove the actions4 menu group
    toolbarGroup = toolbarData.toolbarFind("actions1");         // Locate the actions menu group  
    
    // Add new buttons
    // Note the toolbar is action driven, so we just need to define the correct action name with the button.
    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "Add Row(s)",
        action: "selection-add-row",
        icon: "icon-ig-add-row",
        iconBeforeLabel: true,
        hot: true
    });    
    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "Delete Row(s)",
        action: "selection-delete",
        icon: "icon-ig-delete",
        iconBeforeLabel: true,
        hot: true
    });
    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "Save",
        action: "save",
        icon: "icon-ig-save",
        iconBeforeLabel: true,
        hot: true
    });
    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "My Button",
        icon: "fa fa-american-sign-language-interpreting",
        iconBeforeLabel: true,
        hot: true,
        action: "my_action"
    });
    toolbarGroup.controls.push({
        type: "BUTTON",
        label: "My DA Button",
        icon: "fa fa-play",
        iconBeforeLabel: true,
        hot: true,
        action: "my_da"
    });  

    // Add new select-list
    toolbarGroup.controls.push({
        type: "SELECT",
        title: "Select",
        id: "my_select",
        action: "my_select_action"
    }); 

    // Add a Menu to the toolbar
    toolbarGroup.controls.push({type: "MENU",
        id: "my-menu",
        label: "My Menu",
        icon: "fa fa-navicon",
        iconBeforeLabel: true,
        hot: false,
        action: "custom-menu",
        // Add Menu Items (each additional entry needs a separator)
        menu: {
            items: [{
                type: "action",
                action: "show-highlight-dialog",
                label: "Highlight"
            }, {
                type: "separator"
            }, {
                type: "action",
                action: "show-download-dialog",
                label: "Download"
            }, {
                type: "separator"
            }, {
                type: "action",
                action: function(){ alert('Action 1');},
                label: "Action 1",
                icon: "fa fa-number-1-o"
            }, {
                type: "separator"
            }, {
                type: "action",                
                label: "Action 2",
                action: function(){ alert('Action 2');},
                icon: "fa fa-number-2-o"
            }]
        }
    });

    config.initActions = function(actions){
        actions.add({
            name: "my_action",
            action: function() {
            alert('Hello World');
            }
        });
        actions.add({
            name: "my_da",
            action: function() {
            $.event.trigger('my_da');
            }
        });
        actions.add({
            name: "my_select_action",
            choices: [{ label: "All Jobs", value: "" },
                      { label: "President", value: "PRESIDE" }, 
                      { label: "Manager", value: "MANAGER" },
                      { label: "Analyst", value: "ANALYST" },
                      { label: "Clerk", value: "CLERK" },
                      { label: "Salesman", value: "SALESMAN" }                  
                     ],
            action: function(event, focusElement) {
            var e = document.getElementById("my_ig_ig_toolbar_my_select"),
                value = e.options[e.selectedIndex].value;
                apex.item( "P13_JOB" ).setValue(value);
            }
        });
        }; 

    // Assign new toolbar data back to toolbarData configuration property
    config.toolbarData = toolbarData;

    // Return the options
    return config;
}


The following elements can also be added in the same way, but we will not go into that further here: 
  • Static Text
  • Textfield
  • Radio button
  • Toggle switch

These were very basic examples. Try anything you want. Many things are possible and surly will be fun for you :-)


We hope these tips and tricks will help you. 
If you have questions or suggestions, please leave us a comment ;-)


Here is the demo app for reference.


References:
https://docs.oracle.com/en/database/oracle/application-express/20.2/aexjs/grid.html

Labels: , ,