AJAX Programmierung in APEX-Anwendungen: Wer nutzt noch htmldb_Get?
Erscheinungsmonat |
APEX-Version |
Datenbankversion |
März 2017 |
ab 5.0 |
ab 11.1 |
Der Umgang mit AJAX-Technologie, also dem Absetzen einer separaten HTTP-Abfrage
und dem dynamischen Verändern der APEX-Seite, ist mittlerweile
vielen vertraut. Allerdings zeigen sich in der Praxis recht unterschiedliche
Wege, AJAX umzusetzen. Vor allem in älteren Anwendungen findet sich vielfach noch
die Javascript-Funktion
htmldb_Get.
Im jüngsten Application Express Release 5.1 wurde htmldb_Get
desupported, das ist in den
Release Notes ersichtlich. Aber eigentlich war es noch die wirklich dokumentiert;
die Application Express API Reference enthielt noch nie einen
Eintrag zu htmldb_Get.
Es ist also an der Zeit, sich von htmldb_Get
zu verabschieden - das bedeutet in erster Linie natürlich, dass man es nicht mehr erneut einsetzt. Wenn sich darüber hinaus
eine gute Gelegenheit ergibt, sollten bestehende Vorkommen ersetzt werden.
Daher stellt dieser
Community-Tipp eine gängige AJAX-Problemstellung (Abbildung 1) und aktuelle Lösungsansätze dazu vor.
Abbildung 1: Die Aufgabe: Im Textbereich sollen Informationen zum ausgewählten Eintrag erscheinen
Die Auswahlliste (P1_EMPNO) wird mit den
Spalten EMPNO und ENAME der Tabelle EMP aufgebaut - sobald einer
ausgewählt wurde, sollten, und zwar ohne dass die Seite neu geladen wird, Informationen
zur Auswahl im Textbereich (P1_EMP_INFO) angezeigt werden: das ist eine
ganz klassische AJAX-Aufgabe, mit denen die Alternativen zu htmldb_Get sehr gut aufgezeigt werden können.
1. Dynamic Actions
Das Nutzen von Dynamic Actions ist die mit Sicherheit einfachste und in den meisten Fällen
auch die beste Lösungsvariante. Die gesamte AJAX-Aufgabe wird deklarativ in APEX hinterlegt;
APEX kümmert sich selbst um den nötigen JavaScript-Code. Die nötigen Dynamic Actions
werden wie folgt erzeugt.
- Erstellen Sie im Page Designer eine neue Dynamic Action für das Element P1_EMPNO (die Auswahlliste).
Abbildung 2: Eine neue Dynamic Action erstellen
- Im Property Editor auf der rechten Seite vergeben Sie zuerst einen Namen und legen Sie dann fest,
dass die dynamische Aktion dann ausgeführt
werden soll, wenn die Auswahlliste P1_EMPNO verändert (Change-Event) wird - der neue Wert
darf aber nicht NULL sein (Abbildung 3).
Abbildung 3: Details, wann die Dynamic Action ausgelöst werden soll
- Dann legen Sie fest, was genau passieren soll. Klicken Sie im Strukturbaum links die (noch rot
markierte) TRUE Action an und ändern Sie deren Eigenschaften im Property Editor rechts: Nehmen
Sie setValue als Action und SQL Statement als Set Type. Wählen Sie dann das Element P1_EMP_INFO als Affected Element aus.
Abbildung 4: Aktion "Set Value": Details
- Hinterlegen Sie dann die SQL-Abfrage, mit deren Ergebnis das Element befüllt werden soll. Sie sollte
genau eine Spalte und eine Zeile zurückliefern. Wichtig ist auch, dass Sie das Element P1_EMPNO
bei Page Items To Submit eintragen, damit der in der Auswahlliste selektierte Eintrag auch wirklich
bei der SQL-Abfrage ankommt.
Abbildung 5: SQL Abfrage für die Dynamic Action
Wenn Sie die Seite nun testen, bemerken Sie, dass der Inhalt des
Textbereichs sich ändert, sowie Sie in der Auswahlliste einen neuen
Eintrag wählen. Sie haben Ihre APEX-Seite mit AJAX-Funktionalität
versehen, ohne auch nur eine Zeile Javascript-Code zu schreiben. Und
da die dynamischen Aktionen ein Teil der APEX-Metadaten sind, stehen
alle Informationen dazu in den APEX Dictionary Views zur Verfügung.
Das Ergebnis: Nach Auswahl eines Eintrags erscheinen Detailinformationen in der Textbox
Besser geht es eigentlich nicht - und Dynamic Actions können noch
mehr, als APEX-Elemente zu setzen. Man sollte eigenen Javascript-Code, also
die nun folgende Variante 2, nur dann einsetzen, wenn die Anforderung mit
Dynamic Actions nicht umgesetzt werden kann. Sie werden feststellen,
dass dies nur sehr selten der Fall ist.
2. Manuelle AJAX-Implementierung
Im Vergleich zur bereits besprochenen Variante mit Dynamic Actions
ist die folgende, "manuelle", Vorgehensweise wesentlich aufwändiger. Bevor Sie
loslegen, löschen Sie jedoch die soeben erstellte Dynamic Action oder
sorgen Sie per Bedingung (Condition) dafür, dass sie Nie (Never) ausgeführt wird. Alternativ kann man dafür auch die Erstelloptionen (Build Options) nutzen.
Zuerst wird die serverseitige Komponente, also der Teil, der die SQL-Abfrage ausführt,
erstellt. Hier haben Sie zwei Möglichkeiten: Wenn Ihr AJAX-Prozess vor allem im Kontext einer
APEX-Seite Sinn macht, dann legen Sie den serverseitigen Teil als AJAX-Callback
auf der Seite selbst an. Wenn Sie den serverseitigen Teil dagegen anwendungsweit
verwenden möchten, dann (und nur dann) nehmen Sie einen Anwendungsprozess in den Gemeinsamen Komponenten. Wenn Sie, im weiter unten folgenden Javascript-Teil,
einen Prozess ansprechen, der sowohl als
gemeinsam verwendbarer Anwendungsprozess als auch als seitenspezifischer AJAX Callback existiert,
so verwendet APEX den AJAX-Callback.
- Wenn Sie einen Anwendungsprozess verwenden möchten, gehen Sie wie folgt vor:
Beginnen
Sie in den Gemeinsamen Komponenten mit dem Erstellen eines Anwendungsprozesses.
Erzeugen Sie ihn als On-Demand-Prozess und nennen Sie ihn getEmpInfo (Abbildung 6).
Abbildung 7: Neuen On-Demand-Anwendungsprozess erstellen
Hinterlegen Sie den folgenden PL/SQL-Code und speichern Sie den
Anwendungsprozess danach ab.
Wenn Sie per AJAX ein INSERT, UPDATE oder DELETE ausführen, sollten Sie
mit HTP.P zumindest ein SUCCESS oder
eine andere Statusmeldung zurückgeben, damit
Sie im (folgenden) Javascript-Teil den
Status Ihrer Operation prüfen können.
Achten Sie darauf, dass die Autorisierung des Applicaton Process richtig gesetzt ist. Soll er aus
öffentlichen Seiten (also ohne Anmeldung) heraus verwendet werden, so muss das Attribut
Autorisierung (Authorization)
leer sein (Must Not Be Public User darf nicht
gesetzt sein). Umgekehrt sollte es gesetzt sein, wenn der Anwendungsprozess nur ausgeführt werden darf,
wenn ein User angemeldet ist.
Abbildung 8: Autorisierung des Anwendungsprozesses prüfen - nur bei "öffentlichen" Anwendungen
- Wenn Sie mit einem (seitenspezifischen) AJAX Callback arbeiten, gehen Sie so vor:
Klicken Sie im Page Designer auf der linken Seite den Reiter für das Processing - wo die Seitenprozesse
verwaltet werden. Im Eintrag AJAX Callbacks öffnen Sie das Kontextmenü und klicken Create Process.
Daraufhin erscheint auf der rechten Seite ein neuer AJAX Callback mit einigen Defaults.
Abbildung 9: Neuen AJAX Callback erstellen
Hinterlegen Sie den oben dargestellten PL/SQL Code. Nennen Sie Ihren AJAX-Callback getEmpInfo.
Abbildung 10: Namen und PL/SQL Code für den AJAX Callback hinterlegen
Auch hier gilt, dass Sie Ihr PL/SQL Code in jedem Fall mit HTP.P eine Ausgabe produzieren
sollte - wenn Sie per AJAX ein INSERT, UPDATE oder DELETE ausführen, sollten Sie
zumindest ein SUCCESS zurückgeben, damit Sie im (folgenden) Javascript-Teil den
Status Ihrer Operation prüfen können.
Damit haben Sie die erste Hälfte der "manuellen" AJAX Implementierung, den
serverseitigen Prozess, fertiggestellt. Nun geht es an den browserseitigen Javascript-Teil:
Navigieren Sie zu
den Seitenattributen der Anwendungsseite, und dort zum Bereich Javascript.
Tragen Sie dann bei Deklaration der Funktion und globalen Variable
folgenden Javascript-Code ein.
Die JavaScript-Funktion apex.server.process führt einen AJAX-Request
zum APEX-Server durch. Dies ist die "offizielle", dokumentierte Javascript-Funktion für AJAX-Requests, die
man anstelle von htmldb_Get verwenden sollte.
Die Dokumentation
zu apex.server.process finden Sie bei den
Application Express Javascript APIs.
Als ersten Parameter übergeben Sie den Namen
des Application-Prozesses. Danach kommen übergebene Parameter und APEX-Elemente.
Im Gegensatz zur Dynamic Action-Variante wird das APEX-Element P1_EMPNO
hier nicht an den APEX-Server gesendet - dessen Inhalt wird allerdings
als AJAX-Parameter x01 übergeben. Im
PL/SQL-Code des Anwendungsprozesses wird der Parameter mit
APEX_APPLICATION.G_X01 angesprochen. Sie
können die Parameter x01
bis x10 verwenden - damit steht Ihnen neben
dem Submit eines APEX-Elements noch eine weitere Variante zur Parameterübergabe
an den Server zur Verfügung.
Für die Experten sei noch gesagt, dass das Absenden eines APEX-Elements
sich (natürlich) auf den APEX Session State auswirkt und damit auch zu
COMMITs in der Datenbank führt. Die Parameter x01 bis x10 sind dagegen
einfache PL/SQL-Parameter - wenn Sie also auf dem Server eine große
Last durch AJAX-Prozesse erwarten, ist die Nutzung der "x-Parameter" ressourcenschonender
als ein "Submit" der APEX-Elemente.
Der Bereich success im JavaScript-Code enthält wiederum eine JavaScript-Funktion;
diese wird, wie der Name schon nahelegt, im Erfolgsfall ausgeführt. Im Beispiel
wird einfach das APEX-Element P1_EMP_INFO mit der Server-Antwort des AJAX-Aufrufs
gesetzt (Javascript-Funktion apex.item.setValue). Analog dazu könnte man mit error auch Javascript-Code für den Fehlerfall
hinterlegen. Der Parameter dataType schließlich legt fest, welche Antwort vom
Server erwartet wird - in unserem Fall ist das einfacher Text, daher wird auch
text angegeben. Wenn Sie hier nichts angeben, erwartet apex.server.process, dass
die Serverseite mit JSON-Syntax antwortet.
Der letzte Schritt ist nun, die gerade erzeugte Javascript-Funktion getEmpInfo()
dann aufzurufen, wenn der Endanwender die Auswahlliste P1_EMPNO ändert. Zum Setzen des Event-Handlers können Sie nun, obwohl Sie die gesamte Implementierung bereits mit JavaScript gemacht haben, wieder eine Dynamic Action einsetzen. Diese wird dann wie oben deklariert, als Aktion nehmen Sie dann aber JavaScript-Code ausführen (Abbildung 11).
Abbildung 11: JavaScript-Code per Dynamic Action ausführen
Alternativ können Sie Event-Handler jedoch auch "manuell", allein mit JavaScript Code, setzen und
komplett auf Dynamic Actions verzichten. Tragen Sie dazu
(in den Seitenattributen) unter
Beim Seitenladen ausführen folgende Javascript-Zeile ein.
Starten Sie die Seite und probieren Sie es aus. Sie sollte nun genau so
reagieren, wie vorher mit den Dynamic Actions. Der Unterschied ist, dass
Sie die Implementierung nun manuell gemacht haben. Wie immer ist eine manuelle
Implementierung aufwändiger und in den APEX-Metadaten auch nicht so gut
nachvollziehbar wie das Standard-Vorgehen mit Dynamic Actions. Dafür
bekommt man viele Möglichkeiten, das Verhalten im Detail zu beeinflussen.
Das Ergebnis: Nach Auswahl eines Eintrags erscheinen Detailinformationen in der Textbox
Fazit
Wie schon erwähnt, sind Dynamic Actions das Mittel der Wahl zur Umsetzung
von AJAX-Funktionalität in einer APEX-Anwendung. Komplexere Fälle oder solche,
bei denen das Verhalten im Detail beeinflusst werden soll, lassen sich mit
manuellem JavaScript-Code und der Funktion apex.server.process umsetzen. Sinnvoll kann das bspw. sein, wenn Sie sehr viele Dynamic Actions auf Ihrer APEX-Seite brauchen: Die
Erfahrung hat gezeigt, dass Anwendungsseiten nur noch schwer wartbar sind, wenn die Anzahl der
Dynamic Actions überhand nimmt.
Wie Sie Dynamic Actions und eigenen JavaScript-Code miteinander integrieren können, wurde
bereits
in einem Community-Tipp beschrieben. Schauen
Sie einfach nochmal rein.
Zurück zur Community-Seite
|