Patrick Wolf

Checkboxen in Tabular Form – Ganz Einfach!

Gepostet am 05. Februar 2009

Wie Sie vielleicht wissen sind Tabular Forms in Oracle APEX manchmal ein wenig schwierig. Ihnen fehlen leider manche der Funktionalitäten welche bei Page Items verfügbar sind. Eines davon ist der deklarative Support für Checkboxen. Mit der folgenen Anleitung können Sie Checkboxen in Tabular Forms hinzufügen, ohne die existierende Assistenten generierte Funktionalität zu verlieren.

Warum ist es so wichtig die vorhandenen ApplyMRU/… Prozesse weiterzuverwenden?

Der Grund ist, dass die Standard Prozesse welche durch den Assistenten erzeugt werden viele Dinge automatisch im Hintergrund machen. Sie kümmern sich um “Lost update detection”, Locking und am Schluss natürlich um das Insert/Update/Delete und das ganze ohne, dass man eine Zeile Code schreiben muss. Das Ziel jedes Entwicklers sollte sein, so viel Standard Oracle APEX Funktionalität zu verwenden wie möglich ist. Es muss das Rad nicht immer neu erfunden werden!

Im Netz gibt es verschiedene Lösungen, zum Beispiel die von Denes Kubicek welche auch ganz gut funktionieren, aber leider nicht mit obigem Ziel übereinstimmen. Es muss eine Menge kodiert werden, wobei aber trotzdem die “Lost update detection” und Locking Funktionalität fehlt. Darum habe ich mir eine andere Lösung überlegt, welche nicht die APEX_Item.Checkbox Funktion verwendet.

Die Lösung

  1. Erstellen Sie eine normale Tabular Form (New Page\Form\Tabular Form). Ich verwende für dieses Beispiel die DEMO_USERS Table welche mit der Sample Application erstellt wird.
  2. Ändern Sie die Reihenfolge und den Anzeigetyp (“Display As”) der Spalten so wie Sie sie haben wollen.

    Assistenten generiere Tabular Form nach dem Ändern der Spalten.

    Assistenten generiere Tabular Form nach dem Ändern der Spalten.

  3. Für die Spalte mit dem Flag, in unserem Beispiel ist das ADMIN_USER, setzen Sie die Eigenschaft “Display As” auf “Hidden”
  4. Ändern Sie das SQL Statement der Tabular Form Region (Edit Region\Region Definition\Region Source) und fügen Sie die neue Spalte ADMIN_USER_CHECKBOX hinzu.
    SELECT USER_ID
         , USER_ID AS USER_ID_DISPLAY
         , USER_NAME
         , ADMIN_USER
         , CASE
             WHEN ADMIN_USER = 'Y' THEN 'checked="checked"'
           END AS ADMIN_USER_CHECKBOX
         , QUOTA
         , EXPIRES_ON
         , CREATED_ON
      FROM DEMO_USERS
  5. Setzen Sie für die neue Spalte ADMIN_USER_CHECKBOX die Eigenschaft HTML Expression (Column Attributes\Column Formatting) auf
    <input type="checkbox" #ADMIN_USER_CHECKBOX# value="#ROWNUM#" name="f40" id="f40_#ROWNUM#"/>

    #ADMIN_USER_CHECKBOX# soll der Name der neu erstellten Spalte sein.

  6. Erstellen Sie einen “Seiten Verarbeitungsprozess” mit den folgenden Einstellungen:
    • Typ: PL/SQL
    • Name: Set ADMIN_USER flag
    • Sequence: 0 (Wichtig: Muss vor allen anderen Prozessen sein!)
    • Point: On Submit – Before Computation and Validations
    • Enter PL/SQL Page Process:
      BEGIN
          -- Reset the hidden ADMIN_USER flag for all visible records to N
          -- Note: g_f04 maps to the hidden ADMIN_USER column
          FOR ii IN 1 .. APEX_Application.g_f04.COUNT
          LOOP
              APEX_Application.g_f04(ii) := 'N';
          END LOOP;
      
          -- Set the hidden ADMIN_USER flag for those records where the
          -- checkbox has been set by the user to Y
          -- Note: g_f40 is the checkbox column ADMIN_USER_CHECKBOX
          FOR ii IN 1 .. APEX_Application.g_f40.COUNT
          LOOP
              APEX_Application.g_f04(APEX_Application.g_f40(ii)) := 'Y';
          END LOOP;
      END;
  7. Das war es auch schon wieder! Die Standard Oracle APEX Tabular Form Prozesse werden wie bisher weiter verwendet. Wenn Sie wollen können Sie das obige Beispiel auf apex.oracle.com testen.

    Tabular Form mit Checkbox

    Tabular Form mit Checkbox

Wie funktioniert das Ganze?

  • Schritt 1 – 3 sind die normalen Schritte um ein Tabular Form zu erstellen.
  • Schritt 4 fügt die neue Spalte ADMIN_USER_CHECKBOX hinzu, welche ein interessantes CASE statement enthält.
    CASE
      WHEN ADMIN_USER = 'Y' THEN 'checked="checked"'
    END AS ADMIN_USER_CHECKBOX

    Dieses CASE Statement liefert checked=”checked” zurück wenn ADMIN_USER auf Y(es) gesetzt ist. Diese Art von Wert wird von dem INPUT HTML Tag benötigt, welches wir im Schritt 5 erstellen.

  • Schritt 5 fügt das HTML Tag zum Anzeigen der Checkbox hinzu.
    <input type="checkbox" #ADMIN_USER_CHECKBOX# value="#ROWNUM#" name="f40" id="f40_#ROWNUM#"/>

    Es verwendet die #COLUMN_NAME# Ersetzungssyntax, in unserem Fall #ADMIN_USER_CHECKBOX# um den aktuellen Wert der Spalte zu bekommen. Mit diesem Wert weiss die Checkbox ob sie ein Häkchen anzeigen soll oder nicht.

    Wenn eine Checkbox von einem Benutzer gesetzt wird, dann sagt uns value=”#ROWNUM#” in welcher Zeile das gemacht wurde. Der #ROWNUM# Platzhalter wird durch die Zeilennummer des sichtbaren Datensatzes in der Tabular Form ersetzt. Diese Nummerierung startet immer mit 1 und hat nichts mit der Pseudo Spalte ROWNUM zu tun welche in SQL Statements verwendet werden kann!

    name=”f40″ weist Oracle APEX darauf hin die Checkbox Spalte auf das APEX_Application.g_f40 Array zu mappen. Ich verwende eine sehr hohe Nummer damit die Checkbox nicht in Konflikt mit den “save state” Spalten kommt welche von APEX selbst verwaltet werden. Eine hohe Nummer macht auch deswegen Sinn weil man sich unnötige Code Änderungen spart, wenn eine neue Spalte in die Tabular Form hinzugefügt wird.

  • Schritt 6 erstellt den Prozess welcher die versteckte ADMIN_USER Flag Spalte mit den gesetzten Checkbox Werten von ADMIN_USER_CHECKBOX synchronisiert. Was wird dabei gemacht?Zuallererst müssen wir herausfinden auf welches APEX_Application.g_fxx Array unser verstecktes Flag für die Spalte APEX_USER gemapped ist. Wie das geht finden Sie in dem Artikel Which Tabular Form Column is mapped to which Apex_Application.g_fxx array?. In unserem Beispiel ist das g_f04.Die erste FOR LOOP setzt bei allen sichtbaren Datensätzen der versteckten ADMIN_USER Flag Spalte den Wert zurück auf N(o).
    FOR ii IN 1 .. APEX_Application.g_f04.COUNT
    LOOP
        APEX_Application.g_f04(ii) := 'N';
    END LOOP;

    Im zweiten FOR LOOP wird für alle jene Datensätze die eine gesetzte Checkbox haben das Flag wieder auf Y(es) gesetzt.

    FOR ii IN 1 .. APEX_Application.g_f40.COUNT
    LOOP
        APEX_Application.g_f04(APEX_Application.g_f40(ii)) := 'Y';
    END LOOP;

    Auf den ersten Blick sieht das Statement vielleicht ein wenig komisch aus, aber bei Checkboxen muss man folgende Dinge wissen:

    • Das Array welches zu einer Checkbox gemapped ist enthält nur so viele Einträge wie es auch gesetzte Checkboxen gibt. Zum Beispiel: Wenn Sie 10 sichtbare Checkboxen haben und nur die Checkboxen der Zeilen 8 und 10 gesetzt sind, dann enthält das Array g_f40 nur 2 Einträge mit den Index Positionen 1 und 2!!! Eine normale Spalte wie QUOTA returniert immer ein Array mit 10 Einträgen wo die Index Position immer auf die Zeilennummer verweisst. Unabhängig ob ein Wert eingegeben wurde oder nicht.
    • Darum ist es so wichtig value=”#ROWNUM#” im Schritt 5 zu definieren. Es sagt uns welche Checkbox gesetzt wurde. Der Wert der gesetzten Zeile ist im g_f40 Array gespeichert und wird dazu verwendet die Index Position für das Ändern des g_f04 Array (ADMIN_USER Spalte) zu ermitteln.
  • Weil wir das Array der versteckten Spalte ADMIN_USER mit den gesetzten Checkboxen synchronisiert haben, kann der Standard ApplyMRU Prozess die Werte ganz normal verwenden als wären sie vom Benutzer manuell in einem Textfeld eingegeben worden.
  • Die ADMIN_USER_CHECKBOX Spalte wird vom ApplyMRU Prozess nicht berücksichtigt, weil sie für Oracle APEX als “Standard Report Column” angezeigt wird. Dieser “Display As” Typ ist kein “saves state” Typ und wird daher von den schreibenden Prozessen wie dem ApplyMRU ignoriert. Ehrlich gesagt würde er auch gar nicht wissen auf welches Array die Checkbox gemapped ist.
  • Ein weiterer Vorteil der Synchronisierungsmethode ist, dass das g_f04 Array (welches auf ADMIN_USER gemapped ist) die gleiche Array-Indizierung hat wie die normalen Spalten. Das ermöglicht uns einfacheren Validierungscode zu schreiben, da alle Werte der gleichen Zeile auf der selben Index Position in den verschiedenen g_fxx Arrays ansprechbar sind!

Finale Anmerkung

Warum verwende ich nicht die APEX_Item.Checkbox Funktion im SQL Statement anstatt des selbst geschriebenen HTML Codes in der HTML Expression?

Es gibt einen einfachen Grund: Der AddRows Prozess funktioniert damit nicht. Der Grund dafür ist, dass APEX_Item.Checkbox nur für existierende Datensätze aufgerufen wird aber nicht für neue Datensätze. Darum müssen auch die Lösungen welche APEX_Item.Checkbox verwenden die “Neue Zeile”-Funktionalität nachentwickeln und das machen sie mit einem UNION gegen DUAL wo die WHERE clause auf den aktuellen Request ADD_ROWS eingeschränkt ist. Wobei diese Lösung leider meistens Probleme mit dem Sortieren, usw. hat.

Wie ich es bereits in meinem Eingansstatement gesagt habe.

Erfinden Sie das Rad nicht neu, sondern verwenden Sie so viel bestehende Oracle APEX Funktionalität als möglich!



3 Kommentare zu “Checkboxen in Tabular Form – Ganz Einfach!”

Kommentar schreiben
  1.  

    [...] This posting was originally posted on Der Oracle APEX Experten Blog. [...]

  2.  
    macwadu

    How can i automatically refresh a Tabular Form i used this but it didnt work but it works in a classic report. Where P4_LIST is the static id of the Tabular Form.
    var refreshId = setInterval(function(){ $(‘#P4_LIST’).trigger(‘apexrefresh’); }, 2000);

    Any ideas?

  3. gsonntag 
    gsonntag

    Hi,
    Select the partial refresh of the Tabular Form.

    Lg, Gerhard


Kommentar schreiben