Advanced Application Express: Tips and Techniques

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 65

Advanced Application Express

Tips and Techniques

www.tusc.com/briefing
By Bradley D. Brown
http://bradleydbrown.blogspot.com
Chairman and Chief Architect, TUSC

Abstract
Oracle Application Express is a powerful
and comprehensive tool. Numerous
advanced tips and techniques will be
covered in this presentation. These
topics include: pop-up windows, complex
searches, document management,
indexing and searching, tool tip or hints,
email links, page 0, help text, background
jobs, add to my calendar feature, saving
contacts, sending mass emails, and
more.

Topics
HTML

Favorite Icon
Pop-ups & pass-backs
Tool tips
Anchors

Apex

Page 0
Help text / page
Custom login page
Scrolling text
Document Management
Outlook Integration
Email

PL/SQL

Complex searches
Function-based queries
Background jobs

JavaScript

Setting focus
AJAX
Netflix Flyups
Google Maps

Most everything is in the sample app


Download from www.tusc.com
http://www.tusc.com/oracle/technology/briefing_menu.html

HTML Tips

Favorite Icon

Place favicon2.ico file in

$ORACLE_HOME\Apache\Apache\htdocs

In Page template

<link rel="shortcut icon" href="/favicon2.ico" type="image/x-icon" />

Pop-up windows
Pop-up Window

Target=_blank in Link
Attributes

Custom Pop Ups Returning Multiple Values

Javascript passes the


values back

The Oracle Experts

Bubble-Help, Tool tip or hints

Title attribute in Link Attributes


Title="#COMMENTS#"

Anchors
Anchors can provide direct links to places on a page

Set an anchor anywhere on the page


<a name="Location">

Reference an anchor anywhere


<a href="#Location"> jump to location</a>

Best practice in page template is to include at the top of the body


section

<a name="Top">

This way you can place a return to top link anywhere on the
page

<a href=#Top><img src="/i/themes/theme_8/blue_arrow_up.gif"


alt=Top of page" title=Top of page"></a>

Long Page in App

Application Express Tips

Page 0

Anything placed on Page 0 will appear on every page


by default
Can use Conditional display to turn region on or off
for specific pages, users, etc.

Help text
Page level help text

Create a table HELP_TEXT with help for each page


Spell check your help text

Create a new blank page


Add a new region to the page Help Text
Could also have conditional HTML sections

Add an item to your navigation bar (i.e. Help)


Branch to your help text page (i.e. 10)
Pass &APP_PAGE_ID to P10_PAGE_ID

Item level help text

Open any page item


Enter help text for the item
Spell check your help text

Highlight Current

Note highlighting of current row

Master, master, detail

Key Elements

SQL Report Regions

Link to select current


master record
Detail SQL Query
limited by selected
master row

Hidden Items to
implement details
Custom Templates to
highlight current row

Variation on
alternating color
report template
PL/SQL expression
condition for
selected row

SQL Report Regions


Decode primary key against hidden item for selected
master row
select decode(customer_id,
:P1_CUST_ID, 'CURRENT',
'Select') sel_label,
customer_id,
cust_last_name||', '||
cust_first_name as cust_name,
cust_street_address1||'<br>'||
Cust_city||', '|| cust_state||
' '||cust_postal_code address
from demo_customers
The Oracle Experts

Custom Template

Hidden item used in PL/SQL expression to determine


Selected row
Based off of current themes alternating row report
template
The Oracle Experts

Custom Logon Page

You can create your own logon page for any


application
You can use Oracle Application Expresss built-in
authentication or you can use any existing scheme you
have
Good document on creating a custom logon page:

http://forums.oracle.com/forums/thread.jsp?forum=137&thread
=220034

Document management,
indexing and searching
Documents will be stored in Oracle Application
Express schema
See Sample Application for great code examples
Create a table to store the link to the documents

Create table person_document


(PERSON_ID number,
DOCUMENT_ID number
DESCRIPTION varchar2(4000),
DOCUMENT varchar2(4000))

Show a link to the document


(if there is one otherwise, create new)

Link is to p?n=document_number
select DESCRIPTION, decode(document, null, '<a href="f?p=' ||
:app_id || ':11:::::p11_person_id,p11_document_id:' ||
person_id || ',' || document_id || '">Upload Supporting
Document</a>', '<a href="p?n=' || document || '">Download
Document</a>') document
from PERSON_DOCUMENT
where person_id = :p1_id

Best Practices and Indexing Documents

If you

Might want to port


your application
Have many
documents
Desire to index
document content

Create your own


document table

Create table resumes as


select * from
apex_application_files
Where

Easier to export an
application (and
data) otherwise, its
in Apex schema

Mass Upload of Documents

Create placeholder

CREATE TABLE
TEMP_RESUMES
(NAME VARCHAR2(90),
BLOB_CONTENT BLOB)

Start with directory

Dir /b >resume.ctl

Add SQL*Loader
text above list

Sqlldr user/pass
control=docs.ctl
load data
infile *
into table resumes
fields terminated by ',
(file_name char(50),
blob_content lobfile(file_name)
terminated by eof)
BEGINDATA
a.doc
b.doc

Load up Resumes from Temp_Resumes


INSERT INTO RESUMES
SELECT ROWNUM ID, 0 flow_id, NAME NAME,
NAME filename, NULL title,
CASE WHEN SUBSTR(NAME,LENGTH(NAME)3+1) = 'doc' THEN 'application/msword
WHEN SUBSTR(NAME,LENGTH(NAME)-3+1) =
'pdf' THEN 'application/pdf
WHEN SUBSTR(NAME,LENGTH(NAME)-3+1) IN
('csv','xls') THEN 'application/vnd.ms-excel
WHEN SUBSTR(NAME,LENGTH(NAME)-3+1) =
'gif' THEN 'image/gif
WHEN SUBSTR(NAME,LENGTH(NAME)-3+1) =
'png' THEN 'image/png
WHEN SUBSTR(NAME,LENGTH(NAME)-3+1) =
'jpg' THEN 'image/pjpeg
ELSE 'application/text
END mime_type,

LENGTH(blob_content) doc_size, 'ascii'


dad_charset, 'brownb@tusc.com'
created_by,
SYSDATE created_on, 'brownb@tusc.com'
updated_by, SYSDATE updated_on,
SYSDATE last_updated, 'BLOB'
content_type, blob_content, NULL
LANGUAGE, 'Loaded by BDB in bulk'
description,
NULL file_type, NULL file_charset
FROM TEMP_RESUMES

Loading Documents

Need a process to
move document after
upload
See
http://download.oracl
e.com/docs/cd/B324
72_01/doc/appdev.3
00/b32469/up_dn_fil
es.htm

INSERT INTO
resumes(id,flow_id,name,filename,mime_type
,doc_size,dad_charset,created_by,created_o
n,updated_by,updated_on,last_updated,cont
ent_type,blob_content,description) SELECT
id,flow_id,name,filename,mime_type,doc_size
,dad_charset,created_by,created_on,update
d_by,updated_on,last_updated,content_type,
blob_content,:P20_DESCRIPTION FROM
APEX_APPLICATION_FILES WHERE name =
:P1_FILE_NAME;
DELETE from APEX_APPLICATION_FILES
WHERE name = :P1_FILE_NAME;

Need Procedure to Download Document

CREATE OR REPLACE PROCEDURE download_my_file(p_file in number) AS


v_mime VARCHAR2(48);
v_length NUMBER;
v_file_name VARCHAR2(2000);
Lob_loc BLOB;
BEGIN
SELECT MIME_TYPE, BLOB_CONTENT, name, doc_size
INTO v_mime,lob_loc,v_file_name,v_length
FROM resumes
WHERE id = p_file;
-- set up HTTP header
owa_util.mime_header( nvl(v_mime,'application/octet'), FALSE );
-- set the size so the browser knows how much to download
htp.p('Content-length: ' || v_length);
-- the filename will be used by the browser if the users does a save as
htp.p('Content-Disposition: attachment;
filename="'||replace(replace(substr(v_file_name,instr(v_file_name,'/')+1),chr(10),null),chr(13),null)|| '"');
-- close the headers
owa_util.http_header_close;
-- download the BLOB
wpg_docload.download_file( Lob_loc );
end download_my_file;

Indexing the Documents

Need an Oracle Text index

create index doc_ctxidx on


resumes(blob_content)
indextype is ctxsys.context
parameters ('datastore CTXSYS.DEFAULT_DATASTORE')

You must re-index regularly

begin ctx_ddl.sync_index('doc_ctxidx','2M'); end;

Searching the Index


Create a search field on the page (e.g. p14_search)
Query, joining document to a person
select r.ID, pd.person_ID person_id, NAME, FILENAME, TITLE,
MIME_TYPE, DOC_SIZE, CREATED_BY, CREATED_ON,
UPDATED_BY, UPDATED_ON, LAST_UPDATED,
CONTENT_TYPE, LANGUAGE, r.DESCRIPTION, pd.DESCRIPTION
person_description, FILE_TYPE, FILE_CHARSET,
get_person_attributes(pd.person_id, chr(13)) person_attribute_info,
get_person_docs(pd.person_id, '<br>') all_docs
from resumes r, person_document pd
where contains (BLOB_CONTENT, :p14_search) > 1
and r.id = pd.document(+)

The Results

Outlook (or other) Integration


Add to my Calendar

Industry standard (RFC


2445) ICS format
Mac/Apple iCalendar,
Mozilla Calendar, Outlook,
etc.

Add contact

Industry standard contact


VCF format

Email Links
Mass Email

Campaigns
Reminders
Workflow

Email links

Select statement

select '<a href="mailto:' || me.EMAIL_ADDRESS || '">' ||


first_name || ' ' || last_name || '</a>' Member

Link

Report attributes, pick attribute, link


Link Text = #MEMBER#
Target = URL
URL = mailto:#EMAIL_ADDRESS#

Sending mass emails


I like my own send_email procedure (email me and Ill send it)
CREATE OR REPLACE PROCEDURE Send_Email
(in_mail_server VARCHAR2 DEFAULT 'exchange.tusc.com',
in_sender_email VARCHAR2 DEFAULT 'me@tusc.com',
in_sender_name VARCHAR2 DEFAULT 'My Full Name',
in_recipient_email VARCHAR2 DEFAULT 'brownb@tusc.com',
in_recipient_name VARCHAR2 DEFAULT 'Your Full Name',
in_cc_email
VARCHAR2 DEFAULT 'me@tusc.com',
in_cc_name
VARCHAR2 DEFAULT 'My Full Name',
in_html_flg
VARCHAR2 DEFAULT 'N',
in_subject
VARCHAR2 DEFAULT 'No Subject was Provided',
in_importance
VARCHAR2 DEFAULT 'Normal',
in_body
VARCHAR2 DEFAULT 'No Body for this Email')

Add to my calendar feature


Industry standard (RFC 2445) ICS format

Mac/Apple iCalendar, Mozilla Calendar, Outlook, etc.

Branch to a PL/SQL page


Mime-type is key

The Guts of the Code


htp.init; -- Wipe out the
buffer

htp.print('ORGANIZER:MAILTO:br
ad@tusc.com');

owa_util.MIME_HEADER('text/cal
endar; method=request');

htp.print('DTSTART;TZNAME=MST:
' ||
to_char(nvl(to_date(v('P12_
expires_ON'),'mm/dd/yyyy'),
l_expires_on), 'yyyymmdd')
|| 'T080000');

-- Get the event information


htp.print('BEGIN:VCALENDAR');
htp.print('PRODID:-//Microsoft
Corporation//Outlook 9.0
MIMEDIR//EN');

htp.print('DESCRIPTION:Reminde
r for account expiring');

htp.print('VERSION:2.0');
htp.print('END:VALARM');
htp.print('METHOD:PUBLISH');
htp.print('END:VEVENT');
htp.print('BEGIN:VEVENT');
htp.print('END:VCALENDAR');
end;

Add Contact feature


Industry standard VCF format

Mac/Apple iCalendar, Mozilla Calendar, Outlook, etc.

Similar to ICS
Branch to a PL/SQL page
Mime-type is key

The guts of the contacts

Declare

-- Get the user information

cursor user_cur is

htp.print('BEGIN:VCARD');

select user_name, expires_on,


company, phone,

htp.print('VERSION:3.0');

from

demo_users

htp.print('N:' ||
user_rec.user_name || ';;');

where

user_id = :p14_user_id;

htp.print('ADR;HOME:;;');

htp.print('EMAIL;PREF;INTERNET:' ||
user_rec.email_address);

htp.print('NOTE;ENCODING=QUOTEDPRINTABLE: Expires on ' || user_rec.expires_on ||


' Admin user? ' || user_rec.admin_user || ' Quota: '
|| user_rec.quota);

Begin

-- Get the user data

for user_rec in user_cur loop

htp.init; -- Wipe out the buffer

owa_util.MIME_HEADER('text/xvcard; method=request');

htp.print('REV:20050707T234724');

htp.print('END:VCARD');

end loop;

end;

PL/SQL tips

Complex searches

Multiple search fields

Cant dynamically build the where clause


Must use instr or like statements
If large dataset, recommend:

Indexes on columns
Use like :p1_search || %
Dont use like % || :p1_search || % or instr
Use separate pages / queries / regions for each field queried
Can use Oracle Text (i.e. contains)

Function-based (Complex) Queries

Lets say you want to know

The first and last date you received an RSVP


The number of people who RSVPed each day between

No easy way to execute this query


Build a function-based query

Function
Table and column data types
View based on casted function

The Function
RSVP_FUNCTION
CREATE OR REPLACE FUNCTION rsvp_function
(in_event_no number)

select count(*) count


from

rsvp

where

event_no = in_event_no;

RETURN rsvp_table
PIPELINED IS
out_rec
RSVP_COLUMNS :=
RSVP_COLUMNS(NULL,NULL,NULL,NULL,NUL
L);
TableSet

cursor count_as_of_cur (in_date date)


is
select sum(decode(yn,'Y',1,0)) y,
sum(decode(yn,'N',1,0)) n

RSVP_TABLE;

cursor min_max_cur is

from

rsvp

select min(trunc(rsvp_date)) min_date,

where

event_no = in_event_no

and

rsvp_date <= in_date + 1;

total

number := 0;

max(trunc(rsvp_date)) max_date,
max(trunc(rsvp_date))min(trunc(rsvp_date)) days
from

rsvp

where

event_no = in_event_no;

cursor count_invitees_cur is

RSVP_FUNCTION
BEGIN
-- Figure out the total count of
invited people
for count_invitees_rec in
count_invitees_cur loop
total :=
count_invitees_rec.count;
end loop;

for count_as_of_rec in
count_as_of_cur(out_rec.rsvp_date)
loop
out_rec.y
count_as_of_rec.y;

:=

out_rec.n
count_as_of_rec.n;

:=

out_rec.w
total - count_as_of_rec.y count_as_of_rec.n;

:=

end loop;
for min_max_rec in min_max_cur loop
FOR i IN 1 .. min_max_rec.days+1
LOOP

PIPE ROW(out_rec);
END LOOP;

out_rec.event_no

:= in_event_no;

out_rec.rsvp_date :=
min_max_rec.min_date + i - 1;

END LOOP;
RETURN;
END;

The Data Types


RSVP_COLUMNS and RSVP_TABLE

Columns
CREATE OR REPLACE
TYPE rsvp_Columns AS OBJECT
( event_no number,
rsvp_date date,
y number,
n number,
w number);

Table

CREATE OR REPLACE
TYPE RSVP_Table AS TABLE OF YPO.RSVP_COLUMNS

The View / Query

3 series (yes, no, waiting)


select rsvp_date, y
from table(cast(rsvp_function(:P3_IN_EVENT_NO)
as rsvp_Table))
select rsvp_date, n
from table(cast(rsvp_function(:P3_IN_EVENT_NO)
as rsvp_Table))
select rsvp_date, w
from table(cast(rsvp_function(:P3_IN_EVENT_NO)
as rsvp_Table))

The Results

Apex Add-ons (APIs)

Apex_plssql_job
Apex_collection
Apex_Ldap
Apex_Mail
Apex_Util

Background jobs

apex_plsql_job is a wrapper written around dbms_job


APEX_PLSQL_JOBS is a table containing the job
information for those submitted
Very helpful for those hourly, daily, weekly, etc.
processes

Functions and Procedures


SUBMIT_PROCESS (function)

Submits background PL/SQL, returns a unique job number. Job number is a


reference point for other procedures and functions in this package.

UPDATE_JOB_STATUS

Updates the status of the currently running job. Most effective when called
from the submitted PL/SQL.

TIME_ELAPSED

Determines how much time has elapsed since the job was submitted.

JOBS_ARE_ENABLED

Determines whether or not the database is currently in a mode which supports


submitting jobs to the APEX_PLSQL_JOB package.

PURGE_PROCESS

Cleans up submitted jobs. Submitted jobs stay in the APEX_PLSQL_JOBS


view until either Oracle Oracle Application Express cleans out those records,
or you call PURGE_PROCESS to manually remove them.

JavaScript, AJAX, etc.

JavaScript
JavaScript provides clientside power

Where to Place JavaScript


Functions

Good doc to work from:


http://www.oracle.com/technol
ogy/products/database/htmld
b/howtos/htmldb_javascript_h
owto2.html#ref

Calling JavaScript from a


Button
Add Client-Side JavaScript
Validations
Enable / Disable Form
Elements
Change the Value of Form
Elements

Apex JavaScript - Setting Focus


Check out /i/javascript/apex_html_elements.js for a
complete list of already developed JavaScript
(charCount, setStyle, confirmDelete, hideShow,
GetCookie, SetCookie, html_PopUp, etc)
To focus on an item, make sure to change focus
property in page properties first_field is a build-in
function:
<script type="text/javascript">
first_field('P20_FROM_DATE');
</script>

AJAX and Other DHTML Tricks

AJAX

Asynchronous JavaScript and


XML

Rest

Http get commands


Returns XML

Excellent examples

http://apex.oracle.com/pls/otn/f?p
=11933

Using AJAX
Asynchronous Java Script and XML

Not new technology, just combination of existing


Interacts with the server without refreshing the page

Used a lot in APEX SQL workshop


APEX makes implementation simple
Refresh a variety of objects

Single display item


Multi-value things such as select list
Entire report regions

The Oracle Experts

Using AJAX

Select a value
Populates Job

Select a department
Populates select list

The Oracle Experts

AJAX Key Elements


Item with onChange event
JavaScript function called by onChange

Calls Process using htmldb_Get


Uses results

Application Level Process

On Demand
returns value or XML document

Application Level Items, used in process


Page Zero
The Oracle Experts

AJAX using a Query Process


Two page items
Select list with onChange trigger
Text field to accept value

Select list calls JavaScript function when its value is changed


The Oracle Experts

Netflix Flyups
Netflix uses AJAX to
retrieve its flyups.
For a great thread on how
to implement this, see
http://forums.oracle.com/fo
rums/thread.jspa?threadID
=318874&tstart=0

Google Map Integration

Easy integration
http://www.google.com/apis/maps/documentation/

Summary

Oracle Application Express is powerful


Download the Sample App

Real examples in there


Lots of great code

Forum is helpful and well monitored


Watch for Web 2.0 additions

Where to Get More Information?

Numerous presentations on the TUSC site

Full Day Tutorials


Numerous 1-3 hour sessions
Local Oracle Users Groups

TUSCs Training Center


Oracle Application Express Handbook

by Larry Linnemeyer and Bradley D. Brown


December 2005

Oracle Application Express Forum, Oracle Application


Express Studio, etc.

Want more Information?

Call or email TUSC

800-755-TUSC
sales@tusc.com

Call or email Brad

303-985-2213
brad@tusc.com

Visit our site

http://www.tusc.com
Register for our newsletter

Questions?

Brads Papers and


Presentations
Java-based Oracle Web
Development

Wireless

Practical Portal Practices

Java Server Pages

Implementing JSP in Portal

JavaMail

UltraSearch

Java for the PL/SQL Developer

Search Engines

Web Cache achieving 150 the


performance

Utl_smtp and Utl_http

iFS

JavaScript

Top DBA scripts for Web Developers

Security

9iAS Installation, Configuration, and


Tuning

Special Thanks

Larry Linnemeyer for his advanced topics and all of


his work on the Oracle Application Express book

Other TUSC Presentations and


Papers
Tuning

Database
SQL
Applications

PL/SQL
New Features
Forms, Reports

Security

Designer

Migrations

Team Management

Discoverer & BI

Uncommon Leaders

Built-in Packages

Workflow
DBA topics

Copyright Information
Neither TUSC nor the author guarantee this document to
be error-free. Please provide comments/questions to
bradley_d_brown@tusc.com.
TUSC 2007. This document cannot be reproduced
without expressed written consent from an officer of
TUSC.

You might also like