Mehrere Dateien auf einmal hochladen ...

Eine Datei per APEX-Applikation in eine Tabelle hochzuladen ist nichts Besonderes und wurde schon sehr früh in der Community behandelt. Einfache Dateioperationen werden mittlerweile auch out-of-the-box unterstützt (Declarative Blob Support). Mitunter möchte man dem Endanwender jedoch die Möglichkeit geben, mehrere Dateien auf einmal hochzuladen. Da man im Vorfeld nicht weiß, wieviele Dateien es sein werden, soll man sie per Klick hinzufügen können (Abbildung 1).

Mehrere Dateien auf einmal hochladen

Abbildung 1: Mehrere Dateien auf einmal hochladen"

Im folgenden erfahren Sie, wie Sie einen solchen Dialog realisieren können. Vorab soviel: Für jedes Dateiauswahlfeld benötigen Sie zwingend ein APEX-Formularelement - Sie müssen sich also ein Maximum überlegen und alle Felder als APEX-Formularelemente anlegen. Das ist normalerweise jedoch kein Problem - mehr als 10 bis 15 Dateien wird kaum ein Endanwender auf einmal hochladen wollen; schließlich muss jede Datei einzeln ausgewählt werden. Wenn Sie nach einer Lösung suchen, mit der Sie extrem viele Dateien mit einem Klick hochladen können, ist der Community-Tipp zum Umgang mit ZIP-Archiven vielleicht ganz interessant für Sie.

APEX-Formularelemente erzeugen

Legen Sie nun also soviele Formularelemente zum Upload einer Datei (File Browse) an, wie Sie maximal erlauben wollen. Geben Sie diesen Elementen Namen nach dem Schema PX_ELEMENTNAME_INDEX. Wenn Sie also den Elementnamen P1_FILE verwenden und bis zu acht Dateien gleichzeitig hochladen möchten, nennen Sie Ihre Formularelemente P1_FILE_1 bis P1_FILE_8. Das Ergebnis sollte wie in Abbildung 2 aussehen.

Für jeden möglichen Datei-Upload wird ein Formularelement generiert

Abbildung 2: Für jeden möglichen Datei-Upload wird ein Formularelement generiert

Fügen Sie im Anschluß noch die Schaltfläche zum Absenden des Formulars hier ("Hochladen") hinzu und das Formular ist (vorerst) fertig.

PL/SQL-Logik zum Verarbeiten der hochgeladenen Dateien einrichten

Die ausgewählten Dateien werden (wie immer bei APEX) in die Tabelle WWV_FLOW_FILE_OBJECTS$ hochgeladen. Zugriff darauf haben Sie mit der View WWV_FLOW_FILES. Wenn Sie den oben angesprochenen Declarative BLOB Support verwenden, sorgt APEX automatisch dafür, dass die Dateien in Ihrer eigenen Tabelle landen. In diesem Fall geht das jedoch nicht - Sie müssen das selbst erledigen.

Wenn Sie noch keine Tabelle für Ihre BLOBs haben, erzeugen Sie sich eine. Das folgende Skript erzeugt eine sehr einfache Tabelle BLOB_TABLE und eine Sequenz BLOB_TABLE_SEQ zum Generieren eindeutiger IDs.

create table BLOB_TABLE(
  id        number(10),
  filename  varchar2(1000),
  content   blob
)
/

create sequence SEQ_BLOB_TABLE start with 1 increment by 1
/

Erzeugen Sie nun auf Ihrer Anwendungsseite einen neuen PL/SQL-Prozeß, der beim Absenden der Seite (onSubmit) ausgeführt werden soll. Hinterlegen Sie folgenden PL/SQL-Code:

declare
  C_ELEM_NAME   varchar2(10) := 'P1_FILE';
begin
  for item in (
    select item_name from apex_application_page_items
    where application_id=v('APP_ID') 
      and page_id = v('APP_PAGE_ID')
      and item_name like C_ELEM_NAME || '_%'
  ) loop
    insert into blob_table (
      select seq_blob_table.nextval, filename, blob_content 
      from wwv_flow_files 
      where name = v(item.item_name)
    );
    delete from wwv_flow_files 
    where name = v(item.item_name);
  end loop;
end;

Wenn Sie einen anderen Elementnamen gewählt haben, ändern Sie die Konstante C_ELEM_NAME im declare-Block entsprechend um. Wenn Sie die Seite nun starten, werden Sie feststellen, dass soweit schon alles funktioniert. Sie können beliebig Dateien auswählen (müssen nicht vorne anfangen) und nach einem Klick auf die Schaltfläche Hochladen befinden sich alle ausgewählten Dateien in Ihrer Tabelle.

Das Formular funktioniert bereits - sieht aber noch nicht so gut aus

Abbildung 3: Das Formular funktioniert bereits - sieht aber noch nicht so gut aus

An dieser Stelle könnte man nun aufhören, es funktioniert bereits alles. Allerdings sieht ein solches Upload-Formular nicht so gut aus. Bei der Akzeptanz einer (Web-)Anwendung durch den Endbenutzer kommt es nicht allein auf die Funktionalität an - "das Auge isst mit". Gewünscht ist also ein Formular wie in Abbildung 1, in welchem der Anwender den Eindruck hat, dass die Anzahl der Dateien völlig flexibel ist.

Formularelemente zum Datei-Upload flexibel einblenden

Diese Anforderung soll als letztes mit JavaScript umgesetzt werden. Es läuft im Prinzip auf folgende Vorgehensweise hinaus:

  • Alle Elemente (bis auf das erste) werden zu Beginn ausgeblendet. Dazu wird die CSS-Eigenschaft display auf none gesetzt.
  • Unterhalb jedes Elements wird ein Link mit dem Text Upload another File gesetzt. Der Link verzweigt auf eine JavaScript-Funktion, die das erste versteckte Element mitsamt dessen Link Upload another File aufdeckt. Anschließend wird der Link selbst versteckt.
  • Schließlich wird jedesmal geprüft, ob mehr als ein Element aufgedeckt ist. Ist das der Fall, wird bei jedem Element ein Link Remove eingeblendet - dieser verzweigt auf eine JavaScript-Funktion, die das jeweilige Element versteckt und eine evtl. ausgewählte Datei wieder entfernt.

Laden Sie sich also die JavaScript-Datei multipleFileUpload_JavaScript.js herunter und hinterlegen Sie den Code im Seiten-Header (Abbildung 3). Alternativ können Sie die Datei natürlich auch als Statische Datei hochladen und dann referenzieren (Entfernen Sie dann nur das HTML-Tag <script> zu Beginn und Ende der Datei).

JavaScript-Code in die APEX-Seite einbetten

Abbildung 4: JavaScript-Code in die APEX-Seite einbetten

Wenn Ihnen die englischen Texte Upload another File und Remove nicht gefallen, können Sie diese auch ändern. Navigieren Sie dazu im JavaScript-Code in die Zeilen 11 bis 17 und ändern Sie die Texte (nur die Texte) darin entsprechend um. Achten Sie darauf, dass die darin enthaltenen HTML-Tags (<div> bzw. <a>) intakt bleiben.

 1 function multiFileUpload_init(p_item) {
 2   var l_counter = 1;
 3   while ($x(p_item + '_' + l_counter)) {
 4     if  ($x(p_item + '_' + (l_counter + 1))) {
 5       $x(p_item + '_' + (l_counter + 1)).parentNode.parentNode.style.display = "none";
 6     }
 7     $x(p_item + '_' + l_counter).parentNode.innerHTML =
 8       $x(p_item + '_' + l_counter).parentNode.innerHTML + 
 9       '<span id="' + p_item + '_' + l_counter + '_HIDE" style="display: none;"> ' +
10       '&nbsp;' +
11       '<a class="removeFileUpload" href="javascript:multiFileUpload_hide(\'' + p_item + '\', ' + l_counter + ')">' +
12       'Remove' + 
13       '</a>' +
14       '</span>' + 
15       '<div id="' + p_item + '_' + l_counter + '_UNHIDE"> ' +
16       '<a class="addFileUpload" href="javascript:multiFileUpload_unhide(\'' + p_item + '\')">' +
17       'Upload another file' + 
18       '</div>';
19     l_counter = l_counter + 1;
20   }
21   g_visibleFileUploads = 1;
22 }

Zum Abschluß müssen Sie dafür sorgen, dass die Formularelemente "initialisiert" werden. Navigieren Sie dazu zum HTML Body Attribut und tragen Sie dort folgenden Text ein (Abbildung 5). Wenn Ihre Upload-Formularelemente nicht P1_FILE_X heißen, ändern Sie den Parameter der Funktion entsprechend um. Zusätzlich stellen Sie in den den Cursor-Fokus auf Kein Fokus (do not focus cursor) um. Das geschieht im Abschnitt Display Attributes.

onLoad="multiFileUpload_init('P1_FILE');"
Initialisierung der Formularelemente im "HTML Body Attribut"
Cursor-Fokus abschalten

Abbildung 5: Initialisierung der Formularelemente im "HTML Body Attribut"

Stellen Sie zusätzlich in den Display Attributes den Cursor-Fokus auf Kein Fokus (do not focus cursor) um.

Wenn Sie die Seite nun starten, erscheinen nicht mehr die acht Formularelemente, sondern nur noch eines mit einem entsprechenden Link zum Hinzufügen einer weiteren Datei.

Vorläufiges Ergebnis: Das Hinzufügen und Entfernen von Dateien geht schon

Abbildung 6: Vorläufiges Ergebnis: Das Hinzufügen und Entfernen von Dateien geht schon

Zum Abschluß können Sie das Aussehen der Links mit folgenden CSS-Klassen beeinflussen. Fügen Sie diese an geeigneter Stelle ein - in Frage kommen das Seiten-Template oder der Bereich HTML Header in den Seitenattributen.

<style>
  a.removeFileUpload {font-weight: bold; text-decoration: none; color: red;}
  a.addFileUpload    {font-weight: bold; text-decoration: none; color: green;}
</style>

Wenn Sie die Seite nochmals starten, sehen Sie das Endergebnis, wie eingangs in Abbildung 1 dargestellt. Übrigens ist diese Lösung hinsichtlich der Anzahl der Formularelemente völlig flexibel. Wenn Sie mehr oder weniger haben möchten, fügen Sie einfach entsprechend Elemente hinzu oder löschen Sie welche. Sowohl der JavaScript-Code als auch der PL/SQL-Prozeß reagieren dynamisch. Wichtig ist nur, dass die Indexzahl am Ende (P1_FILE_X) bei eins (1) anfängt und durchgehend ohne Lücken bis zum jeweiligen Maximum hochzählt.

Zurück zur Community-Seite