1. Oracle Forms 11g Integration with JavaScript

In this tutorial we will have a closer look at Oracle Forms and JavaScript in the process using Cascading Style Sheets (CSS) and a popular third party JavaScript library called jQuery.

Approximately 2 hours.

This tutorial covers the following topics:

 

Show all images

Place the cursor over this icon or hit Alt-a (Alt-Shift-a on Firefox) to load and view all the screenshots for this tutorial. Alternatively, you can place the cursor over an individual icon in the following steps to load and view only the screenshot associated with that step. You can hide an individual screenshot by clicking on it.

The demonstration application we will build integrates simple forms with a dHTML menu system that controls both the form and other dHTML objects such as a date picker and an image viewer in the same browser window. With this application we will demonstrate how Oracle Forms can call out to these browser widgets as well as how to call into the Oracle Forms runtime via the Forms client applet. We will also demonstrate how to create JavaScript functions from scratch, at runtime, with client side PLSQL.

Here is a screen shot of the resulting application with Forms, the menu and the datepicker visible.

scr

This demonstration uses a few standards in the web world that may be unfamiliar to Forms developers so what follows is an attempt at defining a few of the terms and standards used.

This acronym stands for dynamic HTML and is an umbrella term for using client side languages like JavaScript or server side languages like PHP and Java Server Pages to create dynamic, as opposed to static, web pages. See this Wikipedia entry for more information.

JavaScript has emerged as the dominant client side scripting language. Like PLSQL it is pointerless but while PLSQL is compiled to byte code it is interpreted. It is imperative, weakly typed, object oriented but protype based rather than class based and functions are first-class entities. See this Wikipedia entry for more information.

CSS stands for Cascading Style Sheets and is the way to define the style of a web site. We will use it to make the applet appear to be a part of the larger browser page. See this Wikipedia entry for more information.

An understanding of the DOM, or Document Object Model, is crucial to be effective when programming in JavaScript. The DOM is the model by which   HTML objects are represented and manipulated. See this Wikipedia entry for more.

Back to Topic List

Before starting this tutorial, you should:

  1. Have access to or have installed Oracle Forms version 11.1.1.

  2. Have access to or install an Oracle database 11g.

  3. Have the scott schema (EMP and DEPT) installed.

    Warning: For security reasons, it may not be advisable to install the sample schemas into a production database. If you do install them, you should use passwords other than default passwords, although default passwords are used in the examples shown in tutorials provided by Oracle. When you are finished using the sample schemas for tutorial and demo purposes, you may drop them by issuing the following SQL*Plus command for each installed sample schema:

    DROP USER <schema_name> CASCADE;
  4. If you are using the sample schemas for the first time, you may find that you must unlock the schema user, and then grant CONNECT and RESOURCE roles to it. You can do this by using Oracle Enterprise Manager, which is part of Oracle.

    Alternatively, you can issue the following SQL*Plus commands:

    ALTER USER scott IDENTIFIED BY tiger ACCOUNT UNLOCK; 
    GRANT CONNECT, RESOURCE to scott; 
    
  5. If you wish to follow along using the finished files perform these steps:

    1. Use Internet Explorer 7 or later. Version 6 of IE and any version of Firefox will not allow the particular JavaScript menu we are basing this tutorial on to show in front of the Forms applet. The Milonic menu can be used with frames however. See this URL for more information on how to accomplish that.

    2. Expand the zip file to a temporary location (per default unzipping it will create a directory called "jsdemo").

    3. From the expanded zip file, copy the fmb files (found in the "MyOracleProjects\js" folder) to a directory of your choice. Open them in the builder, connect as scott and compile them to the same directory as the fmb files.

    4. Set the FORMS_PATH variable in the default.env file to include the directory containing the fmx files.

    5. Copy the js.html(found in the hierarchy starting with the directory called "OracleMiddleware") file to the Forms config directory:

    6. <ora_middleware_home>\user_projects\domains\<name_of_domain_ie_ClassicDomain>\servers\WLS_FORMS\stage\formsapp\11.1.1\formsapp\config
      
    7. Copy the files jsdemo.html, jsdemo.js, jsdemo.css and jquery.js as well as the directories JSCal2, menu, lightbox05, img and transEffects to the Forms directory:

    8. <ora_middleware_home>\user_projects\domains\<name_of_domain_ie_ClassicDomain>\servers\WLS_FORMS\stage\formsapp\11.1.1\formsapp\formsweb.war\
      

Back to Topic List

The first order of business is to use a JavaScript-based menu. It will control the Forms applet and the dHTML objects on the page. We will remove the standard menu in Forms, discover that it cannot fully be removed and then proceed to remove it anyway if only visually.

We will also remove the logo, the background image and the status bar at the bottom of the Forms applet window to make the Forms applet look like its an integral part of the page. Finally we will use a new color scheme called swan to further make the Forms applet blend in.

Forms has support for arbitrarly complex menus. Each menu can recursively contain a sub menu, a menu item, which in turn can contain PLSQL or be a visual part of the menu with no other function. In this example we remove it by setting the form level property Menu Module to null.

  1. In the Forms Builder, click the module node in the Object Navigator and press F4 or select Property Pallette in the Tools menu to open the property sheet for the form module. Find the 'Menu Module' under the Functional heding and erase the default value.

  2. To remove the status bar at the bottom of the applet window at runtime set the console Console Window property (located just above the Menu Module property) to <Null> by selecting it in the dropdown menu:

  3. To further strip the form of elements that give away its origin we'll take away the logo and the background image. To do that we'll create a new section called [javascript] in the formsweb.cfg file. In 11g this is designed to be done in Enterprise Manager. For the sake of simplicity this tutorial will do it directly in the file:

    [javascript]
    splashScreen=no
    background=no
    logo=no
    

    (Hover the mouse over the source code above and click the left most icon in the upper right hand corner to open a window containing a plain text version of the text above. You can also click the second to left most icon that appear to automatically copy the code to your clipboard.)

  4. While we are in the file, lets add some more parameters. Height and width are a little big per default. The new colorscheme called swan fits here so we set colorscheme and lookAndFeel to accomplish that. We also need to make sure that JavaScript support is turned on and we have to name the applet:

    [javascript]
    width=440
    height=300
    splashScreen=no
    background=no
    colorScheme=swan
    lookAndFeel=oracle
    logo=no
    applet_name=forms_applet
    enableJavascriptEvent=true
    baseHTMLjpi=js.html
  5. To have something to show we'll add a default multirecord block of the EMP table. Double-click on the Data Blocks node in the Object Navigator and go thru the Block Wizard to create something like the image below:

  6. Run the application by issuing this in your browser: (note, if using the supplied jsdemo.html you may have to make minor edits to it to point to your own host machine. In jsdemo.html this is defaulted to jcarlin-pc.us.oracle.com)

    http://example.com:9001/forms/frmservlet?config=javascript
    

    This is what you should see:

    The Windows menu is still visible and there is currently no known way to tell Forms to not generate it. To hide it, we need a different approach. To the rescue come JavaScript and CSS.

  7. To accomplish our goal of not having a Forms menu, we have to modify the HTML file from where the Forms applet is launched. Here we make a copy of the basejpi.htm file, call it js.html and save it in the same directory we found the original file:

    <ora_middleware_home>\user_projects\domains\<name_of_domain_ie_ClassicDomain>\WLS_FORMS\stage\formsapp\formsweb.war\
    

    We then wrap the object tag (<object>...</object>) with a div (<div>...</div>), give that div an id=aplt and a class of "nomenu" and add the declarations of that class as below. The object tag is collapsed here to make the screenshot clearer.

    <html>
    <head>
      <title>%pageTitle%</title>
      <style>
      .nomenu {
        position: relative;
        top: -40px;
      }
      </style>
    </head>
    <body %htmlbodyattrs%>
      %HTMLbeforeForm%
      <div id="aplt"><COMMENT>...</COMMENT>
        <!-- Forms applet definition (start) -->
        <object><!-- Content hidden for clarity --></object>
      </div><!-- Wrapping DIV for hiding menu -->
      %HTMLafterForm%
    </body>
    </html>
    
  8. Run the application again and note that the form is now situated higher in the browser and that the menu is not visible.

    What we have done is this: the <div> and the Forms <object> tag it contains is made to have a relative position (the "position: relative" declaration) making it possible to move it up 40 pixels (the "top: -40px" declaration). HTML objects are per default positioned by the browser in a static way and does not respond to changing the bounding coordinates. Setting position to relative makes it possible to move the position relative to where the element would have ended up in the normal, static flow. In this case the div is moved up 40 pixels resulting in that the menu is drawn out side the browser visible pane. See this link [w3.org] for more information about the position declaration in CSS. Search the web for " CSS position relative " for tutorials and demos on the subject.

    This method works in general but doesn't in this case because we plan to show a dHTML menu above the Forms applet and because applets override the Z-order (the depthwise drawing order of elements) rules in popular browser so the Forms menu ends up being visible even though the dHTML menu is placed on top of it. What we need to do is to place the Forms applet in an iFrame and hide the Forms menu under the end of that iFrame.

Back to Topic

Since we cannot remove the generated menu called Windows, we'll need to do something more drastic. What we are going to do is to hide the menu with some CSS. A simple way to do that is to move the Forms applet in under the top of the browser window. Because the JS menu is there that is not possible in this case so we'll use an iFrame to accomplish this.

  1. Create a new html file and save it in the same directory where the altered basejpi file is. Call it "jsdemo.html". The content should be this:

    <html>
    <head>
      <title>JavaScript Integration Demonstration</title>
    </head>
    <body>
      <div id="container">
        <div id="forms">
          <iframe id="forms_iframe" width="465" height="336" frameborder="0" name="forms_iframe" 
            src="http://example.com:9001/forms/frmservlet?config=javascript">
          </iframe>
        </div>
      </div>
    </body>
    </html>
    

    At the outset this file is very simple as you can see. All the Forms related tags are in the nested iFrame. To facilitate placing dHTML components later on, the file contains two extra DIV tags, surrounding the iFrame tag. We'll return to them shortly. Note the name of the iFrame and that the width and the height is larger than the applet's width and height.

  2. Run the application by issuing this in your browser: (note, if using the supplied jsdemo.html you may have to make minor edits to it to point to your own host machine. In jsdemo.html this is defaulted to jcarlin-pc.us.oracle.com)

    http://example.com:9001/forms/jsdemo.html

    We don't need to use the servlet URL because the iframe will do the job of calling the Forms servlet for us.

    The Forms menu is again hidden and we are now free to add a dHTML menu above the apple which will be done in the next section.

To add the menu we need some more html tags in the js.html file:

  1. Add the lines highlighted below

    <html>
    <head>
      <title>JavaScript Integration Demonstration</title>
      <script src="jquery.js"></script>
      <script src="jsdemo.js"></script>
    </head>
    <body>
    <div id="container">
      <div id="menu">
        <script type="text/javascript" src="menu/milonic_src.js"></script>
        <script type="text/javascript" src="menu/mmenudom.js"></script>
        <script type="text/javascript" src="menu/menu_data.js"></script>
        <noscript>
          Menu is only visible when JavaScript is enabled
        </noscript>
      </div>
      <div id="forms">
        <!-- See last code snippet for the content of this tag-->
      </div>
      <div id="footer">
        <!--To comply with the evaluation conditions for the menu system-->
        <a href="http://www.milonic.com/">HTML JavaScript Menu By Milonic</a>
      </div>
    </div>
    </body>
    </html>
    

    The NOSCRIPT tag is there to show something meaningful in case the user has turned off JavaScript in their browser.

    The javascript files necessary to define and draw the menu is brought in by the three SCRIPT tags at lines 10 through 12. We will go thru the parts relevant to get the menu working with Forms next but these files will accompany this tutorial's supporting files rather than appear here in their entirety.

    The SCRIPT tags on lines 10 and 12 and the core files for the menu, necessary for the menu to function correctly and not subject to any customizations and we do not need to understand how they work to make the menu work for our purposes.

    The SCRIPT tag on line 12 is the definition file of the menu and this file we do need to change. This is where we define the menus, the menu items and their behavior when invoked. The important parts of this file , as customized, is listed below. Some parts, denoted with an ellipsis (...) have been omitted for the sake of brevity. The full file is available in the supporting zip file.

    ...
    with(menuStyle=new mm_style()){...}
    with(milonic=new menuname("Main Menu")){ ...
      zindex=2; 
      aI("showmenu=Action;text=Action;"); 
      aI("showmenu=Query;text=Query;"); 
      aI("showmenu=Block;text=Block;"); 
      aI("showmenu=Field;text=Record;"); 
      aI("showmenu=Help;text=Help;"); 
      aI("showmenu=View;text=View;");
    }
    with(milonic=new menuname("Action")){ ...
      aI("text=Save;url=javascript:frmEvent('commit', '' );") ...
      aI("text=Exit;url=javascript:frmEvent('exit', '' );")
    }
    with(milonic=new menuname("Edit")){...}
    with(milonic=new menuname("Query")){ ...
      aI("text=`
        <form action=\"#\" name=srch onSubmit=\"searchInForms();return false;\">Search
        <input type=text name=criteria size=15>
        <input type=\"submit\" value=Go></form>`;
        type=form;"
        );
    }
    with(milonic=new menuname("Block")){...}
    with(milonic=new menuname("Help")) {...}
    with(milonic=new menuname("View")){
      aI("text=Employees;url=javascript:frmEvent('open', 'emp' );");
      aI("text=Departments;url=javascript:frmEvent('open', 'dept' );");
      aI("showmenu=Style;text=Style;");
    }
    with(milonic=new menuname("Style")){
      aI("text=Default;url=javascript:changeSkin2('-');");
      aI("text=Steel;url=javascript:changeSkin2('steel');");
      aI("text=Gold;url=javascript:parent.changeSkin2('gold' );");
      ...
    }
    drawMenus();
    

    This file first defines a style for the menus (omitted in the source above), defines the top level menu structure and then defines the dropdown menus. Each call to the "aI" function defines the type of the entry. Either its a dropdown or a submenu menu (as is the case with the entire top menu and the last menu item in the menu called "View") or a menu item with the text content and the action to be performed when the menu item is selected or its a form (see the second set of highlighted lines).

Back to Topic

Now we will make this menu raise events on the Forms middletier server, the Forms Runtime. To understand how that is accomplished, lets take a look at the first item that uses an url with a javascript call:

aI("text=Save;url=javascript:frmEvent('commit', '' );")

The line defines a menu item which will show the text "Save" and execute the JavaScript function called frmEvent that calls in to Forms and thus creates an event on the Forms Server. To create this function do the following:

  1. Create a new file, call it scripts.js and place it in a directory called "js". Enter this function definition:

    function frmEvent (event, payload) {
    	window.frames["forms_iframe"].document.forms_applet.raiseEvent(event, payload);
    }
    

    Here is where we come in contact with the DOM for the first time. The expression window.frames["forms_frame"] is the way the iframe we created earlier is represented in the browser's page definition. The name of the frame we created is how we reference it in the array ([]) called "frames" belonging to the window object. The reason we need to use the frames array is that we used an iFrame for the Forms applet. That choice makes it possible to hide the menu but also, unfortunately, makes for a more complex javascript code overall.

    The next part of the expression, "document.forms_applet" is the frame's document (a container object for the html document) and then the name we gave the applet in the formsweb.cfg file (forms_applet). The function "raiseEvent" that comes next is defined (and made external) in the Forms applet Java code. This is the Java method that we are after and which does all the work. It takes two parameters: the name of the event and the payload (which can contain any text, XML or JSON or any other text that makes sense). In this case we want to just tell Forms to commit and commits generally don't take any parameters so we leave the payload null.

  2. In the form we now need to handle the event called 'commit'. Here is how you do that. Create a form level trigger called WHEN-CUSTOM-JAVASCRIPT-EVENT and enter this code:

    declare 
      eventName varchar2(30) := upper(:system.javascript_event_name);
      eventValue varchar2(1000) := :system.javascript_event_value;
    begin
      if eventName='COMMIT' then
        commit;
      else
        null;
      end if;
    end;

    In the declare section we get the name of the event ('commit' in this example) by assigning the new system variable :system.javascript_event_name to a local variable after making it all uppercase to exclude the possibility of an accidental mismatch. This system variable is populated by Forms whenever an event comes in just before the trigger is fired. We do the same thing for the payload, or value.

    The IF statement checks if it knows the event name. In this case we have a match so the appropriate PLSQL procedure is called. Note that there is no way to make a procedure call out of a string like you can do in JavaScript (we'll get to that capability of JavaScript later on) so we need this mapping code. If the if statement doesn't know of the event it does nothing which is what the ELSE clause assures. We will later add support for more events to this IF statement but for now we have created a connection between the call we defined in the dHTML menu and the appropriate action or function call in Forms.

    Now lets focus on this line of the menu definition:

    aI("text=`
        <form action=\"#\" onSubmit=\"searchInForms(this, 'criteria');\">
        Search <input type=text name=criteria size=15/>
        <input type=\"submit\" value=Go>
        </form>`;
        type=form;
      ");
    

    This line jams a lot of functionality into one line of javascript so we need to break it down into its components to make it easier to understand.

    First of all it is set up to be an HTML form. The "type" parameter declares that (type=form). Because the text parameter contains quotes the maker of the menu system mandates that the text be "escaped" by surrounding it with backticks ("`") and that any double quotes be escaped by back slashes. If we ignore these two rules we get a menu item of type form that has a html based definition like so:

    <form action="#" onSubmit="searchInForms(this, 'criteria');">
      Search <input type=text name=criteria size=15/>
      <input type=submit value=Go />
    </form>
    

    Rendered in the menu system as the text of the menu item it would look like this:

    This menu item will allow us to enter a search criteria, push the "Go" button and have the function searchInForms() execute (in the example rendering above it resets the input field).

  3. To make this menu item work we need to create this function. Add this to the file scripts.js that we created earlier:

    function searchInForms (htlmForm, elemName) {
      frmEvent('find', htmlForm.elements[elemName].value);
      return false;
    }
    

    The function retrieves the content of the field named "criteria" in the form passed in as "this" which is a system-maintaind variabl that holds the object currently executing. When we call searchInForms() thi points to the form tag which is why we can access the element in the function.

    It then calls Forms via the previously intruduced function frmEvent(), passing in a new event named "find" and the criteria we entered in the HTML field as the payload.

    The function returns false so the normal processing ascociated with submitting a form doesn't take place. We don't want to submit the form to the web server, we want to send an event to the Forms Runtime. Returning false accomplishes that.

  4. To make Forms perform a search we need to add to the trigger we created earlier and create a new event handler in the form.

    declare 
      eventName varchar2(30) := upper(:system.javascript_event_name);
      eventValue varchar2(1000) := :system.javascript_event_value;
    begin
      if eventName='COMMIT' then
        commit;
      elsif eventName='FIND' then
        findEmpByEname(eventValue);
      else
        null;
      end if;
    end;

    The trigger is now set up to handle the new event. It does so by calling a form procedure, passing in the event value.

  5. The final piece of this functionality is to create the procedure findEmpByEname to perform the query in the block.

    procedure findEmpByEname(theName varchar2) is
      whereClause varchar2(300);
      colmn varchar2(50);
      oper varchar2(2);
      literal varchar2(50);
      singleQuote varchar2(2) := '''';
    begin
      if theName is not null then 
        /* there is a criteria specified */
        colmn := 'ename';
        literal := singleQuote || upper(theName) || singleQuote;
        if instr(theName, '%') > 0 then 
          /* support for pattern matching */
          oper := ' like ';
        else /* do an exact match */
          oper := '=';
        end if;
        /* put it all together */
        whereClause := colmn || oper || literal;
      else 
        /* there is no criteria specified so find all employees */
        whereClause := 'empno is not null';		
      end if;
      clear_form(no_validate); /* get to a mode for querying */
      go_block('emp'); /* navigate to the correct block */
      /* set the where clause to find the expected employees */
      set_block_property('emp', default_where, whereClause);
      /* find the rows and display them */
      execute_query;
    end;
    

    Find the explanation of the inner workings of the procedure in the comments. The if statement checking for the presence of a percent sign adds support for the rudimentary pattern matching available in SQL using the like operator. As any PLSQL developer knows: there no such thing as a single single-quote and its better to make one yourself, lest you forget one somewhere and spend hours tracking it down. Thus the quadrupal quote in the declare section.

Back to Topic

Back to Topic List

In this first section we have covered how to hide Forms standard menu and implement a JavaScript based menu system. We have connected this menu to the Forms applet using the raiseEvent method exposed by the applet. Next we will cover calling out to a JavaScript based datepicker and an image scroller.

Hide all images Place the cursor over this icon or press Shift-Alt-h to hide all screenshots.