|
Tipps und Tricks mit manuell erzeugten tabellarischem Formularen
| Erscheinungsmonat |
APEX-Version |
Datenbankversion |
| Januar 2012 |
ab 1.5 |
ab 9.2 |
Die Unterstützung für tabellarische Formulare ist mit jeder APEX-Version besser
und umfassender geworden. APEX 4.1 allein brachte für den Entwickler tabellarischer
Formulare eine Menge äußerst nützlicher Dinge mit:
- Eine explizite Unterstützung für Validierungen - endlich können diese deklarativ festgelegt werden.
- In eigenen PL/SQL-Prozessen können nun Spaltennamen anstelle der etwas umständlichen APEX_APPLICATION.G_FXX-Arrays verwendet werden.
- Eigene PL/SQL-Prozesse können deklarativ pro Zeile oder für das ganze Formular ausgeführt werden.
- Für eigene PL/SQL-Prozesse können Bedingungen pro Zeile festgelegt werden.
Damit können die Assistenten für tabellarische Formulare in immer mehr Situationen
genutzt werden - dass man die Formulare wirklich manuell gestalten muss, kommt immer
seltener vor. Allerdings bleibt es nicht völlig ausgeschlossen: Es gibt immer noch
Situationen, in denen die neuen Möglichkeiten von tabellarischen Formularen nicht
genutzt werden können und die manuelle Arbeit erforderlich ist. Einige Gründe sind
hier aufgelistet ...
- Es existiert bereits ein Bericht mit ggfs. komplexerer SQL-Abfrage und einige
Spalten sollen zu Eingabespalten werden.
- Das tabellarische Formular soll auf mehrere Tabellen angelegt werden und das
Erstellen einer View im INSTEAD-OF Trigger ist nicht gewünscht.
- Mit dem tabellarischen Formular sollen gar keine Tabellen gepflegt werden - vielmehr
sollen PL/SQL-Prozeduren mit den Formulareingaben gestartet werden.
- Man bemerkt während dem Erstellen des Formulars mit dem Assistenten, dass
"es nicht geht" - der Tabelle fehlt ein Primärschlüssel - man möchte noch
zusätzliche Spalten mit SQL-Funktionen hinzufügen und ... und ... und ...
Dieser Tipp widmet
sich daher ausführlich dem Thema "manuelle tabellarische Formulare". Allerdings sollten Sie das hier gelesene nur
dann einsetzen, wenn Sie Ihre Anforderungen mit den APEX-Standardassistenten wirklich nicht umsetzen
können - wenn letztere eine Alternative sind, sind sie die
bessere Alternative. Allein die erwähnten neuen Möglichkeiten mit APEX 4.1
(zeilenweile Validierungen, Verwendung von Spaltennamen im PL/SQL-Prozess) sind
mit dem hier beschriebenen manuellen Ansatz nicht möglich.
Bericht zur Darstellung des tabellarischen Formulars
Zunächst sei festgehalten, dass ein tabellarisches Formular immer ein Bericht ist. Das
Berichts-SQL verwendet das PL/SQL-Paket APEX_ITEM zum Generieren der HTML-Formularelemente
in den Berichtszeilen. Und das kann man auch selbst tun, denn APEX_ITEM ist ein
dokumentiertes, vom Entwickler nutzbares Paket. Der erste Schritt eines komplett manuellen tabellarischen Formulars ist daher
immer der klassische Bericht.
Im folgenden soll ein tabellarisches Formular auf die Tabelle EMP erzeugt werden -
erstellen Sie sich dazu eine APEX-Anwendungsseite mit einem klassischen Bericht. Verwenden
Sie folgendes Berichts-SQL:
Besonders wichtig ist der Parameter p_idx bei den Aufrufen von APEX_ITEM - denn
dies ist die Nummer des jeweiligen APEX_APPLICATION.G_FXX-Arrays, unter dem
Sie die Formulareingaben später abrufen können. Wichtig für jedes auf diese
Art und Weise erzeugtes Formular ist, dass Sie einen eindeutigen Wert pro änderbarer Spalte mit
APEX_ITEM.HIDDEN bereitstellen - den brauchen Sie später zum Identifizieren
der Formularspalten. Die jeweiligen Prozeduren in
APEX_ITEM erzeugen unterschiedliche Formularelemente - schauen Sie sich den
generierten Bericht einfach mal an (Abbildung 1).
Abbildung 1: Der mit "APEX_ITEM" erzeugte Bericht in einer ersten Ansicht
Das hat noch nicht viel von einem tabellarischen Formular: Es ist bis jetzt
ein einfacher, klassischer Bericht - und der generierte HTML-Code wird
dank des standardmäßig aktiven Schutzes vor Cross-Site-Scripting (XSS)
"escaped" dargestellt. Zunächst stellen Sie also die Darstellung aller Berichtsspalten, die
mit APEX_ITEM erzeugt wurden, auf Standardberichtsspalte um - dazu navigieren
Sie zu den Berichtsattributen und dann zu den jeweiligen Spaltenattributen (Abbildung 2).
Entfernen Sie dann noch die Überschriften der "Hidden"-Spalten FORM_MD5 und
FORM_EMPNO - entfernen Sie aber nicht das Häkchen bei Spalte anzeigen.
Abbildung 2: Spaltendarstellung auf "Standardberichtsspalte" umstellen
Nun sieht die Seite schon eher nach einem tabellarischen Formular aus (Abbildung 3).
Abbildung 3: Das tabellarische Formular wird nun richtig dargestellt
Nun geht es daran, die Formulareingaben zu verarbeiten. In diesem Tipp werden
zwei Varianten vorgestellt. Zunächst soll das gelb unterlegte Feld für den ENAME
eine "Sofortänderung" ermöglichen: Sobald man hier etwas ändert und es verlässt,
soll der neue Wert ohne Umweg in die Tabelle geschrieben werden. Diese Technik kann
zur schnellen Änderung von einzelnen Feldern (bspw. "Kommentare") durchaus interessant
sein.
"Sofortänderung" eines Feldes mit AJAX und JavaScript
Beim Aufruf von APEX_ITEM wurden für das gelb unterlegte Feld im Parameter P_ATTRIBUTES
zwei HTML-Attribute mitgegeben: Mit dem Attribut style wurde es gelb unterlegt - und
onBlur sorgt dafür, dass beim Verlassen des Feldes die JavaScript-Funktion
changeEname aufgerufen wird - mit der EMPNO, dem "alten" ENAME und dem Eingabefeld selbst
als Parameter. Diese JavaScript-Funktion wird nun implementiert:
Navigieren Sie zu den Seitenattributen, dort zu JavaScript und tragen Sie den
Code dort ein. Bei älteren APEX-Versionen tragen Sie ihn in den Seiten Header ein;
denken Sie dann aber daran, ihn zwischen die HTML-Tags <script type="text/javascript">
und </script> zu setzen.
Die Funktion wird stets beim Verlassen des Eingabefeldes aufgerufen. Zunächst wird verglichen,
ob der Inhalt überhaupt verändert wurde - dazu war es wichtig, den alten Wert von ENAME mit
der SQL-Abfrage direkt in den JavaScript-Aufruf hineinzugenerieren. Wenn eine
Änderung stattfand, wird mit htmldb_Get ein AJAX-Request ausgeführt und der
Anwendungsprozess changeEname aufgerufen. Die EMPNO, der alte ENAME und
der neue ENAME werden als Paramater x01, x02 und x03 übergeben.
Generell können bis zu 10 "x"-Parameter übergeben werden - Anwendungselemente
sind hierfür also nicht nötig. Der Anwendungsprozess wird bei den Gemeinsamen
Komponenten unter Anwendungsprozesse als Bedarfsgesteuerter Prozess eingerichtet
(Abbildung 4).
Abbildung 4: Erstellen eines Bedarfsgesteuerten Anwendungsprozesses
Hinterlegen Sie folgenden PL/SQL Code:
Probieren Sie es aus - man sieht auf den ersten Blick nicht viel, wenn man
die gelb unterlegten Felder ändert und verlässt. Im Hintergrund tut sich aber
schon etwas - wie Abbildung 5 mit einer Ausgabe der Firebug-Konsole zeigt.
Abbildung 5: Hintergrundaktivität durch den AJAX-Request
Diese Vorgehensweise eignet sich gut, um einzelne Spalten eines APEX-Berichts
für den Endanwender einfach und ohne viel Aufwand änderbar zu machen. "Paradebeispiele"
sind Kommentarfelder, die der Benutzer bei Durchsicht einer Datenreihe schnell
pflegen möchte. Aber auch Auswahllisten für Statusfelder können so einfach implementiert
werden. Es wäre auch möglich, alle Felder auf diese Art und Weise änderbar zu machen;
der Code für die JavaScript-Funktion und den Anwendungsprozess müsste dazu aber
generischer sein.
Noch etwas AJAX: Spalte LOC dynamisch aktualisieren
An dieser Stelle bietet es sich an, das Formular um noch etwas AJAX zu erweitern: Wenn
die Auswahlliste für die DEPTNO geändert wird, soll der Ort in der Spalte LOC ebenfalls
aktualisiert werden (gespeichert wird noch nichts, das geschieht im nächsten Absatz dieses Tipps). Da wir alle Elemente des tabellarischen Formulars selbst kontrollieren,
ist das kein Problem: Zuerst muss das Berichts-SQL angepasst werden. Der Aufruf
von APEX_HIDDEN.SELECT_LIST_FROM_QUERY muss um den Parameter P_ATTRIBUTES erweitert werden.
Nun wird bei jeder Änderung (onChange) die JavaScript-Funktion getLoc aufgerufen. Diese
ruft nun per AJAX-Request den Ort des Departments (DEPT.LOC) ab und trägt ihn in die
Spalte rechts neben der Auswahlliste ein. Damit das von JavaScript aus möglich wird,
muss das jeweilige Feld identifizierbar gemacht werden. Das geschieht, indem dort ein
HTML-Tag mit einem ID-Attribut eingetragen wird. Navigieren Sie also zu den
Berichtsattributen, dort zur Spalte LOC und dann zum Bereich HTML-Ausdruck. Tragen Sie
dort, wie in Abbildung 6 ersichtlich, folgendes ein: <span id="LOC_#EMPNO#">#LOC#</span>.
Abbildung 6: Zeilen in der Berichtsspalte LOC identifizierbar machen
Nun braucht es die JavaScript-Funktion getLoc. Navigieren Sie, wie vorhin, wieder zu den
Seitenattributen, dort zum Bereich JavaScript (wo schon die erste JavaScript-Funktion
vorhanden ist), und setzen Sie diesen Code ein:
Fehlt zum Abschluß noch der Anwendungsprozess zum Auslesen der LOC aus einer Tabelle.
Navigieren Sie zu den Gemeinsamen Komponenten, dort zu den
Anwendungsprozessen und erzeugen Sie wiederum einen Bedarfsgesteuerten
Prozess namens getLoc mit folgendem PL/SQL Code:
Und das ist es! Wenn Sie die Seite nun starten und die Auswahlliste
für die DEPTNO ändern, ändert sich auch der Inhalt der Spalte LOC daneben. AJAX
kann also durchaus auch in einem tabellarischen Formular genutzt werden.
Klassische Verarbeitung des tabellarischen Formulars
Nachdem die "Instant"-Änderung eines Formularfeldes mit AJAX funktioniert,
soll als nächstes die "klassische" Verarbeitung des Formulars mit einem
selbstgeschriebenen onSubmit-Prozess implementiert werden. Dazu wird zunächst
eine Schaltfläche zum Absenden der Seite benötigt. Fügen Sie diese hinzu.
Abbildung 7: Eine Schaltfläche zum Absenden des Formulars wurde hinzugefügt
Die Verarbeitung erfolgt nun in einem "normalen" Seitenprozess, der Beim Weiterleiten
(onSubmit) der Seite ausgeführt wird. Im PL/SQL-Code können Sie auf die Formularinhalte
über die PL/SQL-Arrays APEX_APPLICATION.G_FXX zugreifen, wobei XX für die Zahl steht,
die Sie bei der Berichtsabfrage als Parameter P_IDX vergeben haben. Beachten Sie aber, dass die Arrays nur für Prozesse der Seitenverarbeitung (Page Submit) zur Verfügung stehen; während der onLoad-Phase sind sie immer leer. In diesem Beispiel enthält
das Array ...
- G_F01 die nicht dargestellte EMPNO-Spalte
- G_F02 die Spalte mit dem Gehalt
- G_F03 die Spalte mit den Auswahllisten für die DEPTNO
- G_F10 die Spalte mit den gelb unterlegten Eingabefeldern für ENAME
- G_F50 die nicht dargestellte Spalte mit MD5-Checksummen für das optimistische Locking
Mit diesem Wissen kann der PL/SQL-Prozess erstellt werden. Knüpfen Sie ihn an die
Bedingung, dass er nur ausgeführt wird, wenn die soeben erstellte Schaltfläche geklickt wurde und hinterlegen Sie
folgenden PL/SQL Code ...
Aufmerksame Leser haben wahrscheinlich schon festgestellt, dass sich der Prozess
per Schleife durch das Array G_F01 (das ist die
mit APEX_HIDDEN erzeugte Spalte mit den EMPNO-Werten) durcharbeitet.
- Zunächst wird die MD5-Checksumme anhand der nun aktuellen Daten in der
Tabelle ermittelt. Gleichzeitig werden die Tabellendaten in lokale
PL/SQL Variablen eingelesen.
- Danach wird die Checksumme mit der im SQL-Bericht ebenfalls ermittelten
Checksumme, die im Array G_F50 enthalten ist, verglichen.
- Wenn die
Checksummen unterschiedlich sind, wurde die Tabellenzeile im Hintergrund
geändert (optimistisches Locking). Im Gegensatz zu einem Standard-Tabellenformular
lösen wir nun aber keine Fehlermeldung aus, sondern speichern den Satz
in der APEX-Collection TABFORM_ERRORS ab.
- Danach findet das eigentliche Update statt. Wenn dabei ein Fehler auftritt
(bspw. verletzte Constraints), wird dieser abgefangen und besagte Zeile ebenfalls
in die Collection abgelegt.
Als Ergebnis haben wir ein tabellarisches Formular mit optimistischem Locking,
genauso wie das APEX-Standardformular. Allerdings wird bei auftretenden Fehlern,
keine eigene Fehlermeldung ausgelöst. Vielmehr werden die fraglichen Sätze in
eine Collection geschrieben, die man natürlich auch per Bericht anzeigen kann. Das
Berichts-SQL ist recht einfach - denn aus der View APEX_COLLECTIONS können die Inhalte
der APEX-Collection selektiert werden.
Abbildung 8 zeigt, wie das Nutzerfeedback aussehen könnte.
Abbildung 8: Ein Bericht auf die Collection TABFORM_ERRORS zeigt die Datensätze mit Fehlern an
Und da eine APEX Collection verwendet wurde, muss man sich um das "Aufräumen" nicht
weiter kümmern, das macht APEX von alleine. Der PL/SQL Prozess zum Verarbeiten des
Formulars kann natürlich beliebig programmiert werden - neben dem einfachen Update der
Tabelle EMP sind natürlich noch weitere DML-Operationen, der Aufruf von Stored Procedures
und andere Dinge möglich. Dem Programmierer sind keine Grenzen gesetzt. Auf dem gleichen
Weg sind übrigens auch mehrere tabellarische Formulare auf einer Seite möglich. Eine Begrenzung
stellt lediglich die Anzahl der verfügbaren PL/SQL-Arrays dar - APEX erlaubt maximal 50.
Und da jede
mit APEX_ITEM erzeugte Spalte, in jedem Formular, eine eigene Nummer braucht, darf
es also in allen tabellarischen Formularen einer Seite zusammen nur 50 davon geben.
Fazit
Tabellarische Formulare in APEX können sehr vielfältig sein - neben den APEX-Assistenten
zum Erzeugen standardisierter Formulare kann man immer noch (wie damals mit HTML DB 1.5) komplett
manuell arbeiten. Mit "manuellen tabellarischen Formularen" kann man viele Beschränkungen
umgehen und sogar Eingabefelder unmittelbar (ohne Weiterleiten der Seite) abspeichern, sie
erfordern jedoch mehr Aufwand bei der Entwicklung und sind schwerer wartbar - da die
Details sich im SQL- und PL/SQL Code verbergen. Standardformulare auf der anderen Seite
sind zwar schnell erstellt und leicht wartbar, da deklarativ, bringen jedoch Einschränkungen
mit sich.
In der Praxis empfiehlt es sich, abzuwägen: Können große Teile oder gar die
ganze Anforderung mit Standardmitteln abdeckt werden, so sollte man diese nehmen - bleiben
Lücken oder können sogar wesentliche Teile der Anforderungen nicht abgedeckt werden, so ist
es gut zu wissen, dass man das Problem auf dem manuellen Weg auf jeden Fall lösen kann.
Zurück zur Community-Seite
|