Inside Oracle APEX auf Deutsch (von Patrick Wolf)

Undokumentierte Option für Statische Wertelisten

Habt Ihr gewusst, dass die STATIC und STATIC2 Keywords zum definieren von Statischen Wertelisten in Oracle Application Express (APEX) eine undokumentierte Option haben?

Die Online Hilfe dokumentiert die Verwendung mit
STATIC[2]:Display Value[;Return Value],Display Value[;Return Value]
Aber was machen, wenn einer der Werte einen Strichpunkt oder einen Beistrich (für allen nicht Österreicher, dass ist ein Komma ;-) ) enthält? Dann hat man ein kleines Problem.

In so einem Fall könnt Ihr
STATIC[2](lov-entries-sep,display-return-sep):Display Value[<display-return-sep>Return Value]
<lov-entries-sep>Display Value[<display-return-sep>Return Value]
verwenden. Zum Beispiel:
STATIC2(~,*):Cat, Dog*1~Nemo, Shark*2

Labels: ,


« ... Ganzen Artikel lesen ... »

Anzeigepunkte im Oracle APEX Seiten Template anzeigen

Am Freitag habe ich ein paar Änderungen an einer Oracle Application Express (APEX) Anwendung eines Kunden durchgeführt, welche ich vor einiger Zeit erstellt habe. Ich musste auf einer Seite mit einigen Regionen eine neue neben einer bestehenden erstellen. Normalerweise nicht wirklich ein Problem, man verwendet die "Column" Eigenschaft der Region und damit ist das ganze schon wieder erledigt. Um es kurz zu machen, es hat wegen dem Layout des Templates und der bestehenden Regionen welche auch die "Column" Eigenschaft verwendet haben nicht funktioniert.

Darum habe ich mit der "Anzeigepunkt" Eigenschaft der Region spielen müssen, damit die HTML Tabelle der vorherigen Region "geschlossen" wurde. Dadurch wurde meine Region in einer neuen HTML Tabelle mit ihren eigenen Zellen/Spalten, ... gezeichnet. Aber was ist jetzt der beste "Anzeigepunkt", besonders wenn man mit dem Seiten Template und seinen Regions-Positionsplatzhaltern nicht mehr vertraut ist?

Muss man die Seiten Template Definition öffnen und den HTML Code des Templates nach den #REGION_POSITION_XX# Platzhaltern absuchen? Muss man nicht! Es geht auch anders.

Am Freitag habe ich ein nettes kleines Feature von Oracle APEX wiederentdeckt, ich glaube mich erinnern zu können, dass ich es damals gesehen haben als ich mir Oracle APEX das erste mal angesehen habe, aber auf welches ich total vergessen hatte.

Habt Ihr schon mal auf das "Taschenlampen" Icon neben der "Anzeigepunkt" Auswahlliste gedrückt? Es zeigt eine gerenderte Vorausschau auf das Seiten Template mit allen Positionen der Anzeigepunkte des Templates. Eine hilfreiche Funktion!


Es gibt so viele nette kleine in die Oracle APEX Entwicklungsumgebung eingebaute Funktionen, über die wir uns meistens in unserer täglichen Entwicklungsarbeit gar nicht so bewusst sind. Besonders wenn man schon länger mit dem Tool arbeitet, dann denkt man es zu kennen und ist nicht mehr so Neugierig Dinge auszuprobieren und nach Funktionen zu suchen die man noch nicht verwendet hat. Dabei gibt es so viele nützliche, welche manchmal nur ein wenig versteckt sind! Ich habe schon über ein paar geschrieben, wie z.B.
um nur ein paar zu nennen.

Kennt Ihr andere nette Features welche nicht so oft genutzt werden? Teilt Eure Oracle APEX Builder Tipps und Tricks!

Labels: , , ,


« ... Ganzen Artikel lesen ... »

Auskommentieren von Prozessen/Validations/Branches in Oracle APEX

Während der Entwicklung einer Oracle Application Express (APEX) Applikation kommt es des öfteren vor, dass man einen Prozess, eine Validation, ... auskommentieren will/muss, weil er z.B. kurzfristig nicht funktioniert. Oder ein Anwender sagt, dass er das nicht mehr braucht, man aber weiß, dass man es nächste Woche dann wieder einbaut.

In Oracle Forms war das ganze irgendwie sehr einfach. Dort hat man einfach den Trigger Namen auf Underscores umbenannt (z.B. PRE-QUERY auf PRE_QUERY) und schon hat er nicht mehr gefeuert. Aber wie geht das in Oracle APEX?

Sicher kann man den PL/SQL Code auskommentieren, wenn es sich um einen PL/SQL Prozess handelt, aber dann bitte nicht das NULL; vergessen, damit der Code gültig ist. Wie geht das aber mit den deklarativen Prozessen/Validierungen/Branches/...? Eine Möglichkeit wäre den "Condition Type" auf "Never" zu setzen, dass hat aber den Nachteil eine eventuelle bestehende Condition zu verändern. Außerdem muss man sich das dann auch irgendwo aufschreiben, damit man es beim aktivieren auch wieder richtig setzen kann.

Ich glaube es gibt eine viel elegantere Möglichkeit. Das ganze nennt sich "Build Option".
  1. Unter Shared Component\Build Options eine Neue mit dem Namen "Auskommentiert" erstellen.
  2. Den Status auf "Exclude" setzen.
Damit ist es möglich, jedes Objekt in einer Oracle APEX Applikation "auszukommentieren" in dem man die neue Build Option über die Eigenschaft "Configuration\Build Option" zuweist. Diese Eigenschaft kann schon fast für jedes Object in Oracle APEX gesetzt werden.

Die weitere gute Nachricht ist, dass es sogar einen Report gibt mit dem man sich alle ausdokumentierten Objekte ansehen kann. Einfach mal den "Utilization" Tab unter Shared Components\Build Options ansehen.

Labels: ,


« ... Ganzen Artikel lesen ... »

Ein "verstecktes" Juwel von Oracle Application Express

Oracle Application Express (APEX) hat ein "verstecktes" Juwel (Ok, es gibt noch viele andere auch) welches aber meiner Meinung nicht von vielen Entwicklern verwendet oder gekannt wird.

Seit mal ehrlich, wie oft verwendet Ihr die unscheinbare "Anzeigen/View" Auswahlliste auf der "Page Definition" Seite?

Ihr solltet, denn sie enthält einige hilfreiche Optionen welche Euer Leben wesentlich einfacher machen kann! Aber lasst uns mal einen kurzen Blick auf die verschiedenen Features werfen.

Ereignisse/Events

Das ist ein wirklich hilfreiches Feature, besonders für Oracle APEX Anfänger. Es zeigt einem nämlich für die aktuelle Seite den Ablauf der Ereignisse welche beim Verarbeiten oder der Darstellung einer Seite auftreten. Wenn Ihr die Auswahloption auf "Alles anzeigen" setzt, dann zeigt es Euch auch die Ereignisse die feuern würden wenn Ihr sie definiert hättet. Das hilft einem super das Ereignis zu ermitteln welches man definieren muss damit der Wert z.B. zum richtigen Zeitpunkt gesetzt wird. Ich glaube das ist ein extrem hilfreiches Feature um sich mit den verschiedenen Ereignissen von Oracle Application Express (APEX) vertraut zu machen!

Übrigens, diese Ansicht inkludiert auch die Ereignisse der Seite 0 und die Prozesse auf Applikationslevel. Ich bin nicht sicher ob das immer schon der Fall war, aber zumindest in 3.0.1.x bekommt man ein vollständiges Bild des Ablaufs.

Ein Screenshot von einer der Seiten der ApexLib Beispiel Anwendung welche die verschiedenen Ereignisse zeigt.


Objekte/Objects

Du willst wissen welche Tabellen, Views, Packages, ... von der aktuellen Seite referenziert/benutzt werden? Dieses Feature zeigt sie Dir alle. Die Funktion ist wirklich clever und einfach gemacht um die Abhängigkeiten festzustellen. Sie erstellt temporäre Stored Procedures für alle Code Blöcke und ermittelt dann anhand der Oracle Dictionary Views die Referenzen auf die verschiedenen Objekte.

Ein anderer netter Bonus dieser Funktion ist, dass sie dazu verwendet werden kann um festzustellen ob der PL/SQL und SQL Code syntaktisch korrekt und kompilierbar ist, denn es werden auch alle Code Blöcke angezeigt bei denen es zu einem "Parsing Error" gekommen ist.

Historie/History

Liefert einen schnellen Überblick wer zuletzt die Seite modifiziert hat. Das kann besonders in einem Umfeld mit mehreren Entwicklern interessant sein.

Export

Habt Ihr einen Blödsinn gemacht und die Seite funktioniert nicht mehr? Dann verwendet das Seiten Export Feature in Kombination mit der "As of x minutes ago" Option um die noch funktionierende Version wieder zubekommen.

Erweiterungswunsch: Wie wäre es mit einem "Undo" Feature welches auch die "As of x minutes ago" Option verwendet, aber sofort das Export/Import macht um die Seite wiederherzustellen?

Gruppen/Groups

Verwendet Ihr die Seiten Gruppen Funktion? Wenn nicht, dann solltet Ihr das wirklich mal ansehen! Erstellt sie mit dem "Seitengruppen" Link auf der Seite mit der Übersicht der erstellten Seiten. Die Zuordnung erfolgt dann über die "Seiten Attributen" einer Seite. Die obige Auswahl erlaubt Euch die schnelle Navigation zu den anderen Seiten welche in der selben Gruppe sind!

Referenziert/Referenced

Zeigt alle Objekte welche diese Seite referenzieren. Aber Achtung, es scheint ein kleines Problem mit Links von Bericht Spalten zu geben und es werden auch jene Seiten nicht angezeigt wo in einer HTML Region oder einem SQL Statement ein manueller Link erstellt wurde. Für einen vollständigeren Überblick schaut Euch mal das "Page Flow Diagram" Feature des ApexLib Frameworks an.

Zuletzt angezeigte Seite

Die letzten Einträge der Auswahlliste enthalten die letzten paar angezeigten Seiten für eine schnelle Navigation zu diesen.


Wo was denkt Ihr? Habe ich Eure Aufmerksamkeit geweckt um mal einen genaueren Blick auf dieses Feature zu werfen, damit Ihr es in Eurer täglichen Entwicklung verwendet?

Siehe auch


Labels: , , , , ,


« ... Ganzen Artikel lesen ... »

Ausgewählten Tree Eintrag hervorheben

Während der DOAG APEX SIG Veranstaltung wurde ich gefragt wie man bei einer Tree Darstellung in Oracle APEX den aktuell ausgewählten Eintrag hervorheben/markieren kann.

Nach einer kurzen Nachdenkpause über das Problem hat es sich herausgestellt, dass es eine sehr einfache Lösung gibt, wenn man die Tree Query mit ein wenig HTML Code verbindet.

  1. Erstelle eine normale Tree Region.
  2. Erstelle eine Form Region die mit dem Tree synchronisiert werden soll.
  3. Ändere die Tree Query, damit sie das folgende CASE Statement enthält
    SELECT EMPLOYEE_ID AS ID
    , MANAGER_ID AS PID
    , CASE
    WHEN EMPLOYEE_ID = :P4_EMPLOYEE_ID THEN
    '<span style="color:white;background-color:blue;">'||
    LAST_NAME||
    '</span>'
    ELSE
    LAST_NAME
    END AS NAME
    , 'f?p=&APP_ID.:4:'||:SESSION||'::NO::P4_EMPLOYEE_ID:'||EMPLOYEE_ID AS LINK
    , NULL AS A1
    , NULL AS A2
    FROM #OWNER#.EMPLOYEES
Wie funktioniert das ganze?

Wenn der Tree gerendered wird, dann vergleicht das CASE Statement für den aktuell verarbeiteten Tree Eintrag/Datensatz die EMPLOYEE_ID mit dem aktuell in der Form (P4_EMPLOYEE_ID) angezeigten Datensatz.
Wenn die zwei IDs übereinstimmen, dann wird dem LAST_NAME noch ein SPAN verpasst, welches die notwendigen Style Informationen für die Anzeige beinhaltet.

Einfach, oder? :-)

Schaut Euch die lauffähige Demo des Beispiels an.

Labels: , , ,


« ... Ganzen Artikel lesen ... »

SQL Workshop - Commands: Tastenbelegung

Habt Ihr gewusst, dass man in der Textarea der SQL Commands Seite, Ctrl+Return dazu verwenden kann um das aktuelle SQL Statement auszuführen?

Das ist wirklich viel besser, als immer die Maus verwenden zu müssen um auf den Run Button zu drücken, besonders wenn man die Tastenkombination vom PL/SQL Developer/TOAD gewöhnt ist.

Labels: , ,


« ... Ganzen Artikel lesen ... »

URL in einem neuen Fenster öffnen

Ihr wollte einen Button oder einen Navigationslisteneintrag erstellen welcher einen URL in einem neuen Browser Fenster öffnet?

In reinem HTML würdet Ihr normalerweise einfach
<a href="http://url/" target="_blank">

schreiben. Aber wie kann man das target="_blank" in Oracle APEX angeben, wenn es nur die Eigenschaft "URL Target" gibt, in der man nur einen URL eingeben kann?

Sicher könnte man sich auch mit ein wenig Javascript Code behelfen um ein neues Fenster zu öffnen. Hört sich aber ein wenig kompliziert für so eine einfache Aufgabenstellung an, oder? Es muss auch einen einfacheren Weg geben!

Es gibt ihn auch!

Ihr könnt die gleiche Technik wie für eine SQL Injection verwenden. Einfach
http://url/" target="_blank
in die "URL Target" Eigenschaft schreiben. APEX fügt dann das schließende Hochkomma nach _blank hinzu, den es denkt der URL endet dort. Auf diesem Weg generiert APEX ein gültiges a href Tag mit einem target.

Labels: , ,


« ... Ganzen Artikel lesen ... »

Ein Gantt-Chart mit SQL erstellen

For ein paar Tagen hat Lucas Jellema von AMIS ein wirklich interessantes und nettes SQL Statement auf seinem Blog beschrieben mit dem es möglich ist ein Character based Gantt-Chart zu erstellen.

Ich finde das demonstriert wieder mal sehr gut die unendlichen Möglichkeiten und die Flexibilität von SQL. Schaut es auch an!

Labels: , , ,


« ... Ganzen Artikel lesen ... »

SMS an ein Handy schicken

Heute habe ich einen Artikel im Grant Rolands seinem Blog über SMS from Oracle Forms through a Web-Service gelesen.

Ich habe mir gedacht, es wäre nett so etwas auch in Oracle APEX und PL/SQL zu haben. Kann man ja für Eskalationen oder System Fehler, ... verwenden.

Grant verwendet ein Web-Service von Esendex, aber ich bin mir sicher es gibt genügend andere SMS Gateway Anbieter. Google liefert jedenfalls einige Angebote für Deutschland. Zuerst habe ich mir gedacht ich verwende auch das angebotene Web-Service und schreibe einen PL/SQL Wrapper dafür oder ich verwende die Web-Service Funktion von APEX.

Aber ich habe mich dann dafür entschieden die einfache HTTP POST Version zu verwenden, welche auch von Esendex angeboten wird. Gründe? Warum soll ich mir das ganze Java rundherum antun und es nur unnötig kompliziert und fehleranfällig machen wenn es einfach auch geht. Die APEX Web-Service Funktion konnte ich nicht verwenden, weil ich das ganze ja auch von PL/SQL zum Beispiel in einem Batch-Job verwenden wollte.

Der Code ist eigentlich sehr einfach. Holt Euch ein Gratis Konto, ersetzt die Konstanten in der Beispiel Prozedur und los geht es!

Hinweis: Wenn Ihr einen Proxy habt, dann müsst Ihr den Kommentar für die Proxy Zeile entfernen. Es gibt auch eine sicherere Version mit HTTPS, aber die benötigt wieder ein Wallet, ... eigentlich wollte ich ja nur zeigen wie einfach es ist und das es funktioniert. Die Fehlerbehandlung in der Prozedur könnte sicher auch noch verbessert werden, aber das ganze soll ja nur ein Grundgerüst sein! :-)

Viel Spass beim aufwecken Eurer Bereitschaft/DBAs in der Nacht! ;-)

Um eine SMS zu schicken, einfach die Prozedur mit
BEGIN
sendSMS('+436991812345','this is a test');
END;
aufrufen.

Nachfolgend die Beispiel Prozedur:
CREATE OR REPLACE PROCEDURE sendSMS
( pRecipient IN VARCHAR2
, pBody IN VARCHAR2
)
IS
ESENDEX_USERNAME CONSTANT VARCHAR2(40) := 'your_username';
ESENDEX_PASSWORD CONSTANT VARCHAR2(40) := 'your_password';
ESENDEX_ACCOUNT CONSTANT VARCHAR2(40) := 'your_account';
--
vRequest Utl_Http.req;
vPostText VARCHAR2(500);
vResponse Utl_Http.resp;
vResponseText VARCHAR2(2000);
vErrorText VARCHAR2(200);
BEGIN
----------------------------------------------------------------------------
-- Build text for the post action.
-- For a field description, see
-- http://www.esendex.com/secure/messenger/formpost/SendSMS.aspx
----------------------------------------------------------------------------
vPostText :=
'EsendexPlainText=YES' ||CHR(38)||
'EsendexUsername=' ||Utl_Url.escape(ESENDEX_USERNAME, TRUE)||CHR(38)||
'EsendexPassword=' ||Utl_Url.escape(ESENDEX_PASSWORD, TRUE)||CHR(38)||
'EsendexAccount=' ||Utl_Url.escape(ESENDEX_ACCOUNT, TRUE)||CHR(38)||
'EsendexRecipient='||Utl_Url.escape(pRecipient, TRUE)||CHR(38)||
'EsendexBody=' ||Utl_Url.escape(pBody, TRUE);
----------------------------------------------------------------------------
-- if you need to set a proxy, uncomment next line.
----------------------------------------------------------------------------
/* Utl_Http.set_proxy('proxy.it.my-company.com', 'my-company.com'); */
----------------------------------------------------------------------------
-- Send SMS through the Esendex SMS service.
----------------------------------------------------------------------------
vRequest := Utl_Http.begin_request
( url => 'http://www.esendex.com/secure/messenger/formpost/SendSMS.aspx'
, method => 'POST'
);
Utl_Http.set_header
( r => vRequest
, name => 'Content-Type'
, value => 'application/x-www-form-urlencoded'
);
Utl_Http.set_header
( r => vRequest
, name => 'Content-Length'
, value => LENGTH(vPostText)
);
Utl_Http.write_text
( r => vRequest
, data => vPostText
);
vResponse := Utl_Http.get_response(vRequest);
IF vResponse.status_code = '200'
THEN
Utl_Http.read_text(vResponse, vResponseText);
--
IF vResponseText NOT LIKE 'Result=OK%'
THEN
vErrorText := vResponseText;
END IF;
ELSE
vErrorText := 'HTTP status: '||vResponse.status_code||'-'||vResponse.reason_phrase;
END IF;
--
Utl_Http.end_response(vResponse);
--
IF vErrorText IS NOT NULL
THEN
RAISE_APPLICATION_ERROR(-20001, 'Sending SMS failed with '||vErrorText);
END IF;
END sendSMS;


Labels: , , , ,


« ... Ganzen Artikel lesen ... »

Automatisch aktualisierte Flash Charts in APEX 3.0

Habt Ihr bereits die neuen Flash Charts von Oracle APEX 3.0 verwendet?

Wie auch bereits für SVG Charts ist es möglich eine automatische Aktualisierung alle x Sekunden durchzuführen. Aber es sieht so aus als wäre ein nettes kleines Feature der SVG Charts vergessen worden, nämlich den letzten Zeitpunkt der Aktualisierung anzuzeigen.

Aber wie können wir das Hinzufügen?

Auf den ersten Blick schaut es nicht so einfach aus, den es wird kein komplettes Seiten Refresh gemacht, sondern das Flash Chart wird mittels AJAX aktualisiert.

Aber auf den zweiten Blick ist es nicht so kompliziert, wenn man die dynamischen Features von JavaScript kennt. Oracle APEX erstellt einen Timer, welcher die APEX JavaScript Library Funktion apex_RefreshChart alle x Sekunden aufruft.
<script type="text/javascript" language="javascript">
function chart_r1258481816185669517_InitRefresh(pNow) {
setTimeout("chart_r1258481816185669517_InitRefresh(true)",5000);
if (pNow){apex_RefreshChart (1, '1258481816185669517', 'en-us');}
}

apex_SWFFormFix('c1258481816185669517');
addLoadEvent(chart_r1258481816185669517_InitRefresh(false))
</script>
Aber wie können wir den apex_RefreshChart Aufruf abfangen um einen "Letzte Aktualisierung" Zeitstempel auf der Seite zu aktualisieren?

Es ist sehr Einfach wenn man weiß wie! :-)

In JavaScript können Funktionen wie Variablen erstellt und referenziert werden. Zum Beispiel kann man mit
var vOldFunction = apex_RefreshChart;
eine Referenz auf die Funktion apex_RefreshChart bekommen, welche man dann auch mit vOldFunction aufrufen kann. Nett, oder? Aber wie hilft uns das jetzt bei obigem Problem?

Es erlaubt uns die existierende Funktion apex_RefreshChart durch eine neue Version zu ersetzen welche die zusätzliche Funktionalität abdeckt, aber danach die Original Funktion aufruft um die APEX Funktionalität zum aktualisieren eines Charts auszuführen.
  1. Öffne die "Region Definition" des Flash charts.
  2. Danach im "Region Source" den folgenden JavaScript Code for dem existierendem <object classid=... hinzufügen
    <script type="text/javascript">
    var vOriginal_apex_RefreshChart = apex_RefreshChart;

    apex_RefreshChart = function(page_id,region_id,browser_lang)
    {
    document.getElementById("last_refresh").innerHTML = Date();
    vOriginal_apex_RefreshChart(page_id, region_id, browser_lang);
    };
    </script>
  3. Danach im "Region Footer" den folgenden HTML Code hinzufügen, welcher als Platzhalter für den "Letzte Aktualisierung"'s Zeitstempel gilt.
    <br>
    <center>
    Chart will refresh every 5 sec.<br>
    Last refresh: <span id="last_refresh"></span>
    </center>
Was macht der ganze Code jetzt?

Er überschreibt die existierende APEX Library Funktion apex_RefreshChart mit einer neuen Version welche auch den aktuellen Zeitpunkt in dem SPAN Element mit der id "last_refresh" setzt. Übrigens, wenn Ihr die Default Konvertierung der Date() Funktion nicht mögt, schaut Euch die diversen JavaScript Quellen im Internet an um weite Formatierungsoptionen zu bekommen.

Der obige Code ist ein gutes Beispiel um zu demonstrieren wie man die bestehenden JavaScript Funktionen von APEX erweitern/ersetzen kann um eigene Funktionalität hinzuzufügen.

Wollt Ihr ein Beispiel von dem ganzen sehen? Dann schaut mal auf meine Beispiel Seite.

Labels: , , ,


« ... Ganzen Artikel lesen ... »

Nützliche Oracle APEX Tools

Habt Ihr gewusst, dass mit der Oracle APEX Distribution ein paar nützliche kleine Tools ausgeliefert werden?

Das "Command Line Export" Tool kennt Ihr vielleicht schon. John Scott hat vor einiger Zeit einen Artikel dazu erfasst.

Aber habt Ihr gewusst, dass es noch zwei weitere Scripts gibt, welche manchmal sehr nützlich sein können?
  • apxxepwd.sql im Hauptverzeichnis. Dieses Script kann dazu verwendet werden um das Passwort des ADMIN Benutzers von APEX zu setzen, zum Beispiel wenn man es vergessen hat. Jornica, danke für diesen Tipp!
  • \utilities\reset_image_prefix.sql kann verwendet werden den "Image Prefix" Pfad (das /i/) einer existierenden APEX Installation zu ändern.

Labels: , ,


« ... Ganzen Artikel lesen ... »