Call now: 252-767-6166  
Oracle Training Oracle Support Development Oracle Apps

 
 Home
 E-mail Us
 Oracle Articles
New Oracle Articles


 Oracle Training
 Oracle Tips

 Oracle Forum
 Class Catalog


 Remote DBA
 Oracle Tuning
 Emergency 911
 RAC Support
 Apps Support
 Analysis
 Design
 Implementation
 Oracle Support


 SQL Tuning
 Security

 Oracle UNIX
 Oracle Linux
 Monitoring
 Remote s
upport
 Remote plans
 Remote
services
 Application Server

 Applications
 Oracle Forms
 Oracle Portal
 App Upgrades
 SQL Server
 Oracle Concepts
 Software Support

 Remote S
upport  
 Development  

 Implementation


 Consulting Staff
 Consulting Prices
 Help Wanted!

 


 Oracle Posters
 Oracle Books

 Oracle Scripts
 Ion
 Excel-DB  

Don Burleson Blog 


 

 

 


 

 

 

 
 

Using ApEx (HTML-DB) with AJAX

Oracle Tips by Steve Karam

Putting the Express Back Into Oracle Application Express with AJAX

Oracle Application Express (ApEx) has all the makings of a wonderful product.  It provides rapid development, it's easy to learn, and best of all, it's free.  The one critical thing that has been missing from the Application Express product is speed for the end user.

While anyone can jump in, and with a weekend's time make a basic page with a report, a couple branches, and a validation or two, the more experienced developer realizes that when it comes to the client, speed is of the essence. 

While adding more features, processes, and pages is easy and can make for stunning applications, it ends up slowing down the experience for anyone actually using the apps.  The purpose of this presentation is to show that Application Express users can have their cake and eat it too.  With Application Express and AJAX, the developer can create   high-content pages without the need for page refreshes in order to pull data from the database.

In this presentation, we'll be talking about an application that provides:

-    A drop down list of all employees in the HR system

  A text box that narrows down the employees shown in the drop down by last name

The Old Web

The application above is easy enough to make in the old way.  A drop down list would be populated on page load, optionally based on any criteria from the text box that is used to narrow down employees.  When a user wishes to narrow down the list, they will simply type some characters into the text box, press Submit, and the page will refresh with a new select list that reflects their entry.

Once a user has selected an employee from the drop down list, the page would once again refresh via the onChange JavaScript call or by pressing another Submit button.  Depending on the user's selection and the way the application is designed, it will once again build a page and display the end user's choice along with any supporting information; for instance, a report on employees.

It sounds simple enough, and it works fine!  We've been using this style of Internet for years, and it hasn't given us much trouble, right?

However, think of the complexities of your average web page.  There are dozens of links, buttons, form items, tabs, and drop downs.  A process such as buying an item from an e-store can take many pages, as can forms for complex report criteria.

Let's examine the flow of ye Olde Web:

 

 

 

 

 

 

 

 

 

 

 

 

Figure 1.  Normal Web Flow

And so we repeat again and again.  Every time a button is pressed, or a user form is entered, any time data should come from the database in response to a user request, the web server must build a new page and return the result to the end user.

JavaScript and Oracle

JavaScript alone can alleviate this problem to some degree.  With JavaScript, developers are able to create validations to ensure that proper form elements were filled in.  JavaScript can also be used to populate select lists dynamically, provided the data to be populated is built into the page made by the web server.  It can swap images and do countless other things, but it falls short with one major fault:

JavaScript runs on the client computer.

This presents us with a major issue!  We cannot dynamically pull data from the database, or read server side files, or use any other features requiring our web server or database server.  If the page built by the web server does not contain everything the end user could possibly require, the page must be refreshed in order to build a new page providing additional data.

Let's Talk About AJAX and Oracle

AJAX stands for Asynchronous JavaScript and XML.  Asynchronous is defined as 'Lack of temporal concurrence; absence of synchronism.'  This means we get to make our web requests and view web pages, just as we did in the old method.  However, we also get to perform actions between the client and web server throughout the process!  Our model will change to the following:

 

 

 

 

 

 

 

 

 

 

 

 

Figure 2.  Web Flow with AJAX

Note that we are still making our initial request to the web server, which calls the database and builds the page.  However, the page comes packed with a very special bit of code.  This code is written in JavaScript, and it allows us to make calls back to the web server to request new information while the page is already on the client's computer.

The only difficulty of this method is the data that gets returned to JavaScript.  Because JavaScript is client side, it does not care what server side programming language is run: PHP, JSP, ASP, Application Express, et al.  JavaScript can make a call to these languages just as it would call any other page; however, returning multiple data at a single time in an array native to JavaScript cannot always be accomplished.  There are two methods of dealing with this issue:

XML and Oracle

XML, or eXtensible Markup Language, is able to fit large amounts of data into a single stream.  This steam looks like HTML, but is made up of custom nodes and attributes.  A simple XML structure may look like this:

<EMPLOYEES>
  <EMP_ROW>
    <EMP_ID>333</EMP_ID>
    <EMP_NAME>Steve Karam</EMP_NAME>
  </EMP_ROW>
  <EMP_ROW>
    <EMP_ID>334</EMP_ID>
    <EMP_NAME>O. Racle</EMP_NAME>
  </EMP_ROW>
</EMPLOYEES>

This output can be returned as a single stream to the JavaScript that made the call and decoded using JavaScript's parsing components.  This is where the X in AJAX comes into play.

Serialization, XML and Oracle

Serialization is the act of bringing data together into a single packet that can be returned to JavaScript.  Technically, XML can be a form of serialization, but it is in fact a markup language and therefore is more robust.  Most applications will use a serialization method such as JSON (JavaScript Object Notation) as a means of returning data to JavaScript.  This method is widely used since it is very easy to both serialize (implode) and deserialize (explode).  An example of JSON can be seen here:

'employees': [

  {'emp_id': '333', 'emp_name': 'Steve Karam'},

  {'emp_id': '334', 'emp_name': 'Oracle'}

]

Even though this method does not use XML, it is still called AJAX by definition.  AJAS or AJAJ just doesn't have the same pizzazz.

Enough Theory!  How Does Application Express Do It?

The Application Express implementation of AJAX uses a combination of JavaScript and PL/SQL for processing.  The JavaScript part is performed with an object (class) built into Application Express called htmldb_Get.

The htmldb_Get object can be used to call other Application Express pages or shared processes (we'll talk about these later).  Using the function, we are able to asynchronously make requests and return data to the JavaScript code.  This data can be in any form we like including XML, a single string, or even generated HTML to be displayed as-is.

For instance, if we have a simple page in our application that displays a report, nothing more, like so:

Figure 3.  Report Results

We can call this page using the htmldb_Get object and pull the HTML into our JavaScript function for display.  We'll see how operations such as these are accomplished soon.

First, let's cover the main components of using AJAX with APEX.

The JavaScript for Oracle APEX

JavaScript can be defined in many places on an APEX page.  We can define it for each region in the Region Source area, or in the HTML Header area of a page's attributes.

Our JavaScript will take the form of functions that we will call during certain page actions (we'll call them Activators), which we will cover later.  Take a look at this example function, used to call a shared process that returns serialized data to populate a SELECT list.  The code itself is defined in a region that holds a text field called P1_EMPLOYEE_NARROW and a select list called P1_EMPLOYEES.

<script language="JavaScript1.1" type="text/javascript">
function getEmployeeList (narrowText, empSelect)
{
  var empSelectObj = document.getElementById(empSelect);
  var ajaxRequest = new htmldb_Get(null,&APP_ID.,'APPLICATION_PROCESS=getEmployees',0);
  ajaxRequest.add('P1_EMPLOYEE_NARROW',narrowText.value);
  ajaxResult = ajaxRequest.get();
  if(ajaxResult)
    { 
      empSelectObj.options.length = 0;
      var empArray = ajaxResult.split("~empsep~");
      for(var i=0; i < empArray.length; i++) {
        var colArray = empArray[i].split("~colsep~");
        empSelectObj.options[i] = new Option(colArray[1], colArray[0]);
      }
    }
    else
    {
      empSelectObj.options.length = 0;
    }
  ajaxRequest = null;
}
</script>

This function accepts two variables, 'narrowText' and 'empSelect.'  In this case, narrowText is a textbox that will be passed along, as we shall see.  empSelect is a SELECT list element.  The first thing we do upon entering the function is finding and initializing the actual SELECT object itself as empSelectObj.

Once this is complete, we call the most important of JavaScript functions for AJAX within APEX:  htmldb_Get.

The first argument for htmldb_Get is object_id, but this is not important for our use, and so we leave it null.  The second argument is the application_id, which is contained in the &APP_ID. APEX variable.  The third is the request we wish to make, which is to call an APPLICATION PROCESS called getEmployees (we will see this in detail soon).  The final argument is page number, which we are not concerned with.  This is used if you plan on pulling back another APEX page from the request.

Once we have initialized the htmldb_Get object as ajaxRequest, we are ready to begin.  We will use the ADD method to pass variables along to the destination of the call (which we just found out is getEmployees).  We must call the 'add' method with a name value pair; in this case, we pass a variable called P1_EMPLOYEE_NARROW with the value of the narrowText variable we passed into the JavaScript function.

Finally, a new object called ajaxResult is instantiated as the result of a method of ajaxRequest called get().  This method actually makes the HTTP request and pulls back the results.

The lines that follow are a small but complicated mess of splitting up the serialized object that is returned by its separators and stuffing all the values neatly into an array of options for the SELECT list.

Once you have mastered the use of htmldb_Get and its methods, you can truly do anything within APEX using AJAX.  The most difficult part is figuring out just what kind of data you need to be returned, and deciding how to bring it back.

The source of the data is easy; in this case, it's the shared application process.

The Shared Application Process for APEX and AJAX

These processes can be created in APEX under the Shared Components area.

Figure 4.  Shared Application Processes

When creating a new application process, the most important part is making sure the process is set to run 'On Demand:  Run this application process when requested by a page process.'

The beauty behind this type of process is that they are not part of any page flow.  They do not require anything but basic input, and they output data via a function called htp.prn, which is simply a method of displaying data back to the process that called it.  This means JavaScript can easily call it without being 'attached' in any way, and asynchronously receive the return data.

In our example, we will use the following PL/SQL code for our getEmployees shared application process.  If you do not remember the getEmployees process, look in the JavaScript explanation above.  We supplied this name to the htmldb_Get object as the Request.

declare
  lv_Employee_List varchar2(32000) := '';
begin
  begin
    for i in (select employee_id, last_name || ', ' || first_name employee_name from employees where upper(last_name || ', ' || first_name) like upper(:P1_EMPLOYEE_NARROW) || '%' order by last_name, first_name) loop
      lv_Employee_List := lv_Employee_List || '~empsep~' ||
      i.employee_id || '~colsep~' ||
      i.employee_name;
    end loop;
    lv_Employee_List := substr(lv_Employee_list, 9, length(lv_Employee_List));
  exception when no_data_found then null;
  end;
  htp.prn(lv_Employee_List);
end;

Here we see that our Shared Application Process is nothing more than a harmless PL/SQL block.  The block begins by setting a variable called lv_Employee_List.  This variable will hold our final output.

Next we begin a standard for-loop cursor, but looking at the query we can see it's not so standard after all.  My horrible coding practices here are one reason (Never use functions and concatenations on the left side of a WHERE clause!), but the other is the use of the :P1_EMPLOYEE_NARROW bind variable.  Where did this variable come from?

Remember in the JavaScript when we used the ?add? method of htmldb_Get to define a name value pair?  This is the variable we created that comes from a text box on the page itself.

For each iteration of this loop, we concatenate the query results (employee_id, last_name, first_name) into the lv_Employee_List variable using the ~empsep~ and ~colsep~ delimiters (yes, it would have been easier to just use pipes or commas).  Once the loop is complete, the lv_Employee_List is cleaned up by the substr function (the first ~empsep~ is removed).

Finally, the htp.prn call is made, passing in the lv_Employee_List variable.  htp.prn is nothing truly special; simply a way for a PL/SQL process to return data to ?a call.?  In addition, there's a function called htp.p; it's just like prn except it produces a carriage return at the end of each call.

The Activator

All this is great, just great.  However, without anything in place to call our JavaScript, we are still not getting anywhere.

This is where our activator comes in.  Based on the JavaScript code and the PL/SQL Shared Application Process, you may have deduced that our code is going to use a text field to narrow down a SELECT list.  That being the case, our activator will probably be the text field (P1_EMPLOYEE_NARROW).  Every time someone types text, we want to: call the JavaScript function, which in turn asynchronously calls a PL/SQL block, which returns code to the JavaScript that is put into our SELECT list without any page refreshing.  Exciting, isn't it?

Do not worry; we're almost there!  We already have the JavaScript in place that will take a variable and pass it on to a PL/SQL process, take the result, and populate a SELECT list.  Now we just need to define the objects themselves.

We will define two objects in the same region for which I defined the JavaScript code.  I called it Employee Selection, but the name is not important.

P1_EMPLOYEE_NARROW - Text Box

P1_EMPLOYEES - Select List

Don't worry about state saving for the text box or branches and redirects for the select list.  Remember, we?re looking for 0 refreshes!

The P1_EMPLOYEE_NARROW text box is an ordinary text box except for a single field.  The ?HTML Form Element Attributes? has been set to:

onKeyUp="javascript:getEmployeeList(this, 'P1_EMPLOYEES');?

The onKeyUp action says that whenever focus is on the object and we depress and release a key, the function should be called.  The getEmployees function (which we defined earlier) is called, passing in 'this' as the narrowText parameter and ?P1_EMPLOYEES? as the empSelect parameter.  The 'this' variable simply means to pass the form element making the call: in this case, the P1_EMPLOYEE_NARROW field.  The P1_EMPLOYEES string is passed in, and as we saw above it will be instantiated to an object in the JavaScript with the document.getElementById method.

The Grand Finale

We now have everything we need in order to make AJAX work for us.  To summarize:

-   A JavaScript function that uses page elements as input and makes an asynchronous call to a remote process or page using the htmldb_Get class.

-   A PL/SQL Shared Application Process that uses input from the JavaScript function and prints a serialized result back to the JavaScript code.

-   An activator on a form field that calls the JavaScript when we wish for something to occur.

Using this code, we should see the following result:

Figure 5.  Employee List

Figure 6.  Employees Narrowed by Last Name Field

Figure 7.  Results Further Narrowed Down

Conclusions on Oracle Application Express and APEX

While other methods exist to narrow down searches, the method shown above is only a sampling of what can be produced with Application Express and AJAX.  Learning how to use htmldb_Get is key; with it, you can do nearly anything.

While this walkthrough may seem complex or time consuming, it really is quite simple once you wrap your mind around it.  It took roughly 10 minutes to produce the demo that I created to provide the code for this white paper.  With a bit more time, you can incorporate much more, such as dynamic reports like the one below into your applications.

 

Figure 8.  Dynamic Report Based on Employee

No refreshes required!  The only real change here is the htmldb_Get function.  Instead of calling an application process, we called a page that contained nothing but a hidden variable for our report query and the report itself.  In this case, I created a region for the report to pull into, and used this line to instantiate htmldb_Get:

var ajaxRequest= new htmldb_Get(null,&APP_ID.,null,2);

Note that in this case we do not pass an APPLICATION_PROCESS.  We leave that null and instead pass a page number (2) as the final parameter.  The ?add? method can still be used to pass parameters to the page that's being requested.

If you ever get stuck writing AJAX code for APEX, do not despair.  JavaScript can be extremely difficult to get used to if you?re not accustomed to it, and some Internet software does not provide adequate resources for debugging.  I would recommend Firefox if you plan on writing serious JavaScript code.  In addition, if you get stuck, the folks at the Application Express forum on http://forums.oracle.com are extremely helpful.  You may also want to check out Carl Backstrom's blog at http://blogs.oracle.com/carlback.  His APEX demo app has plenty of great examples of the many uses of AJAX with Application Express.

About the Author

Steve Karam is a Sr. Consultant for Burleson Oracle Consulting and Training, and is responsible for troubleshooting dozens of high profile databases including RAC clusters.  He is also an accomplished instructor, and teaches dozens of courses for Burleson Consulting.

Mr. Karam has the honor of being both the second Oracle 10g Certified Master in the world and an Oracle ACE.  He enjoys helping others in the Oracle Community through writing, Q&A, and through meetings and events as the President of the Hampton Roads Oracle User's Group.   Mr. Karam is also an avid supporter of the Oracle Academy, Oracle's high school education initiative, as he began his Oracle career while in high school. Steve also enjoys blogging on his website, http://www.oraclealchemist.com, when time permits.

Steve lives in Virginia Beach, VA with his wife and two adorable children.  As a family, they enjoy the frequent travels the consulting life can sometimes demand.  They also enjoy movies, outdoor fun, and driving anywhere with the top down.
 

If you like Oracle tuning, see the book "Oracle Tuning: The Definitive Reference", with 700 pages of tuning tips and scripts. 

You can buy it direct from the publisher for 30%-off and get instant access to the code depot of Oracle tuning scripts.


 

 

��  
 
 
Oracle Training at Sea
 
 
 
 
oracle dba poster
 

 
Follow us on Twitter 
 
Oracle performance tuning software 
 
Oracle Linux poster
 
 
 

 

Burleson is the American Team

Note: This Oracle documentation was created as a support and Oracle training reference for use by our DBA performance tuning consulting professionals.  Feel free to ask questions on our Oracle forum.

Verify experience! Anyone considering using the services of an Oracle support expert should independently investigate their credentials and experience, and not rely on advertisements and self-proclaimed expertise. All legitimate Oracle experts publish their Oracle qualifications.

Errata?  Oracle technology is changing and we strive to update our BC Oracle support information.  If you find an error or have a suggestion for improving our content, we would appreciate your feedback.  Just  e-mail:  

and include the URL for the page.


                    









Burleson Consulting

The Oracle of Database Support

Oracle Performance Tuning

Remote DBA Services


 

Copyright © 1996 -  2020

All rights reserved by Burleson

Oracle ® is the registered trademark of Oracle Corporation.