Logo Oracle Deutschland   Application Express Community
Arbeiten mit dem APEX 5.0 Kalender - Teil 1
Erscheinungsmonat APEX-Version Datenbankversion Cloud oder on Premise
Januar 2016 5.0 ab 11.2 on Premise und Cloud

Eine Kalenderansicht gehört zum Standardumfang vieler Anwendungen - dementsprechend stellt APEX seit der ersten Version einen Kalender bereit. Mit APEX 5.0 wurde dieser allerdings gründlich modernisiert: APEX setzt nun auf dem populären jQuery-Plugin FullCalendar auf. Die alte Kalender-Komponente steht noch als Legacy Calendar bereit, sollte aber nur in Ausnahmefällen verwendet werden. Das Erstellen einer Kalender-Komponente ist genauso einfach wie bisher: Als Datenquelle dient eine SQL-Abfrage und mit Einstellungen wird die Kalenderansicht konfiguriert.

Dieser Tipp stellt das Arbeiten mit dem APEX Kalender vor: Zunächst wird eine einfache Kalenderregion erstellt, diese wird dann um wiederkehrende Ereignisse erweitert und schließlich wird Drag & Drop für Ereignisse realisiert. Im zweiten Teil des Tipps werden wir dann näher auf die Javascript-API von jQuery FullCalendar eingehen und vorstellen, wie man eine Kalenderregion komplett manuell erstellen und so über die Möglichkeiten von APEX hinausgehen kann.

Eine einfache Kalenderregion erstellen

Zunächst braucht es eine einfache Tabelle mit ein einigen Zeilen. Legen Sie diese wie folgt an. Wichtig sind vor allem ein Primärschlüssel und Spalten für Beginn und Ende des Ereignisses.

create table tab_events(
  id          number(10) generated always as identity primary key,
  title       varchar2(200) not null,
  descr       varchar2(500),
  start_date  date,
  end_date    date,
  event_type  varchar2(20)
)
/

insert into tab_events (title, descr, start_date, end_date, event_type)
values ('Web Seminar','Ein Onlineseminar zum neuen Produkt', to_date('20160208110000','YYYYMMDDHH24MISS'), to_date('20160208120000','YYYYMMDDHH24MISS'), 'WEB')
/
insert into tab_events (title, descr, start_date, end_date, event_type)
values ('User Group Veranstaltung','Ein Treffen der User Group', to_date('20160210080000','YYYYMMDDHH24MISS'), to_date('20160210170000','YYYYMMDDHH24MISS'), 'USERGROUP')
/
insert into tab_events (title, descr, start_date, end_date, event_type)
values ('Web Seminar','Ein Onlineseminar zum neuen Service', to_date('20160215110000','YYYYMMDDHH24MISS'), to_date('20160215120000','YYYYMMDDHH24MISS'), 'WEB')
/
insert into tab_events (title, descr, start_date, end_date, event_type)
values ('Gruppenmeeting','', to_date('20160215140000','YYYYMMDDHH24MISS'), to_date('20160215170000','YYYYMMDDHH24MISS'), 'INTERN')
/

Legen Sie danach eine Kalenderregion wie folgt an.

Kalender-Region mit dem Page Designer erstellen

Abbildung 1: Kalender-Region mit dem Page Designer erstellen

Hinterlegen Sie die folgende SQL-Abfrage - im wesentlichen selektieren wir die Zeilen der erzeugten Tabelle TAB_EVENTS. Achten Sie darauf, auch den Primärschlüssel zu selektieren, der wird später, beim Drag & Drop, benötigt.

select
  id,
  title,
  descr,
  start_date,
  end_date,
  case 
    when event_type='WEB'       then 'apex-cal-green' 
    when event_type='USERGROUP' then 'apex-cal-red' 
    when event_type='INTERN'    then 'apex-cal-blue' 
  end as css_class
from tab_events

Nehmen Sie bei Attributes die folgenden Einstellungen vor.

Speichern Sie Ihren Kalender ab und starten Sie die Seite. Mit sehr wenig Aufwand haben Sie Ihrer Anwendung einen Kalender mit modernem Look & Feel hinzugefügt.

Kalender-Region: Monatsansicht

Kalender-Region: Wochenansicht

Kalender-Region: Tagesansicht

Abbildung 2: Kalender-Region: Ansichten

Interessant ist die einfache Formatierting mit CSS-Klassen - eine Ergebnisspalte der SQL-Abfrage muss dazu einfach nur den Namen einer CSS-Klasse zurückliefern. Diese Spalte wird dann in den Kalenderattributen als CSS Class deklariert, woraufhin der Kalender eben diese CSS-Klasse für die Ereignisse anwendet. APEX liefert einige vordefinierte CSS-Klassen für gängige Kalenderfarben mit, aber natürlich können Sie auch eigene verwenden. Geben Sie dann anstelle des Namens apex-cal-{farbe} einfach einen eigenen Namen an - natürlich muss eine solche CSS-Klasse auch definiert sein.

Wiederkehrende Termine aufnehmen

Oft soll ein Kalender nicht nur konkrete Ereignisse aus einer Tabelle, sondern zusätzlich wiederkehrende Ereignisse anzeigen. So könnte die Anforderung bestehen, bspw. jeden Mittwoch um 12:00 Uhr ein zweistündiges Ereignis (Generiertes Ereignis) anzuzeigen. Man muss nicht alle diese Ereignisse in die Tabelle TAB_EVENTS eintragen; man kann auch Ereignisse "on-the-fly" erzeugen.

Dazu braucht es zuerst eine SQL-Abfrage, welche - ganz ohne Tabelle - eine Liste von Ereignissen erzeugt. Sehr hilfreich ist hier die SQL-Funktion NEXT_DAY, die, ausgehend von einem bestehenden Datum und einer Wochentagsangabe, das Datum des nächsten Wochentags zurückgibt. Kombiniert man dies mit einem "Zeilengenerator" (SELECT ... FROM DUAL CONNECT BY LEVEL <= X), dann könnte die Abfrage in etwa wie folgt aussehen.

select 
  0 - level as id,
  next_day( 
    to_date('2016-01-01 12:00:00','YYYY-MM-DD HH24:MI:SS'), 
    to_char(DATE'2016-01-06', 'day') -- der 6.1.2016 ist ein Mittwoch
  ) + (level - 1) * 7 as start_date,
  next_day( 
    to_date('2016-01-01 14:00:00','YYYY-MM-DD HH24:MI:SS'), 
    to_char(DATE'2016-01-06', 'day') -- der 6.1.2016 ist ein Mittwoch
  ) + (level - 1) * 7 as end_date,
  'Generiertes Ereignis' as title,
  'Mit SQL-Funktionen generiert' as descr,
  'css_generated' as css_class
from dual connect by level <=52
/

        ID START_DATE          END_DATE            TITLE
---------- ------------------- ------------------- --------------------
        -1 06.01.2016 12:00:00 06.01.2016 14:00:00 Generiertes Ereignis
        -2 13.01.2016 12:00:00 13.01.2016 14:00:00 Generiertes Ereignis
        -3 20.01.2016 12:00:00 20.01.2016 14:00:00 Generiertes Ereignis
        -4 27.01.2016 12:00:00 27.01.2016 14:00:00 Generiertes Ereignis
         : :                   :                   :

Das Ergebnis ist eine Liste mit 52 Ereignissen: An jedem Mittwoch im Jahr 2016 findet Generiertes Ereignis von 12:00 bis 14:00 Uhr statt. Diese SQL-Abfrage kann nun mit der eigentlichen Kalender-Query per UNION ALL verknüpft werden.

select
  id,
  title,
  descr,
  start_date,
  end_date,
  case 
    when event_type='WEB' then 'apex-cal-green' 
    when event_type='USERGROUP' then 'apex-cal-red' 
    when event_type='INTERN' then 'apex-cal-blue' 
  end as css_class
from tab_events union all (
select 
  0 - level as id,
  'Generiertes Ereignis' as title,
  'Mit SQL-Funktionen generiert' as descr,
  next_day( 
    to_date('2016-01-01 12:00:00','YYYY-MM-DD HH24:MI:SS'), 
    to_char(DATE'2016-01-06', 'day')
  ) + (level - 1) * 7 as start_date,
  next_day( 
    to_date('2016-01-01 14:00:00','YYYY-MM-DD HH24:MI:SS'), 
    to_char(DATE'2016-01-06', 'day')
  ) + (level - 1) * 7 as end_date,
  'css_generated' as css_class
from dual connect by level <=52
)

Nun sieht der Kalender wie folgt aus:

Kalender-Region mit on-the-fly erzeugten Ereignissen

Abbildung 3: Kalender-Region mit on-the-fly erzeugten Ereignissen

Achten Sie in der SQL-Query nochmals auf die CSS-Klasse - für die generierten Ereignisse wurde css_generated verwendet, was keine von APEX vordefinierter CSS-Klasse ist. Also definieren Sie diese selbst. Navigieren Sie zu den Seitenattributen, in den Abschnitt CSS, dort zu Inline und hinterlegen Sie folgenden CSS-Code.

.fc .fc-event.css_generated {
  background-color: #eeeeee;
  border-color: #800000;
  color: black;  
}

Daraufhin wird Ihre Kalenderregion etwas anders aussehen. Und natürlich ist das nicht nur für generierte Ereignisse, sondern auch für solche aus der Tabelle TAB_EVENTS möglich - ändern Sie einfach die in der SQL-Abfrage verwendeten CSS-Klassennamen und hinterlegen Sie dann entsprechende Definitionen.

Eigene CSS-Stylings für bestimmte Ereignisse

Abbildung 4: Eigene CSS-Stylings für bestimmte Ereignisse

Drag & Drop

Schon APEX 4.2 unterstützte das Verschieben von Ereignissen im Kalender mit Drag & Drop - das geht natürlich auch mit APEX 5.0. Allerdings ist die Umsetzung viel leichter als früher: Es werden keine eigenen Anwendungsprozesse mehr benötigt; der PL/SQL-Code zum Aktualisieren der Tabelle kann direkt in den Attributen der Kalenderregion hinterlegt werden.

Navigieren Sie also zu den Attributen der Kalenderregion und stellen Sie dort das Attribut Drag & Drop auf Yes. Daraufhin werden zwei weitere Attribute angezeigt - einmal eine Auswahlliste für den Primärschlüssel und ein Textfeld für den PL/SQL-Code, welcher das veränderte Ereignis in der Tabelle abbilden soll.

Drag & Drop aktivieren

Abbildung 5: Drag & Drop aktivieren

APEX macht es dem Entwickler sehr einfach und stellt den Primärschlüssel des vom Benutzer verwendeten Ereignisses sowie die neuen Zeitstempel für Beginn und Ende als APEX-Variablen bereit. Mit diesen Inhalten kann dan ein einfaches SQL UPDATE auf die Tabelle TAB_EVENTS gemacht werden. Für unser Beispiel sieht der Code also sehr einfach und wie folgt aus.

begin
  update tab_events set 
    start_date = to_date(:APEX$NEW_START_DATE, 'YYYYMMDDHH24MISS'),
    end_date =   to_date(:APEX$NEW_END_DATE,   'YYYYMMDDHH24MISS')
  where id = :APEX$PK_VALUE;
end;

Das war's schon - wenn Sie nun speichern und den Kalender neu starten, können Sie bereits damit beginnen, die Ereignisse per Drag & Drop zu verschieben.

Kalender Drag & Drop "in Action"

Abbildung 6: Kalender Drag & Drop "in Action"

Nach Abschluß der Drag & Drop Operation läuft der PL/SQL-Code los und ändert die Spalten START_DATE und END_DATE der Tabelle TAB_EVENTS entsprechend um. Allerdings können auch die "generierten" Ereignisse per Drag & Drop verschoben werden - der PL/SQL Code wird dann wirkungslos bleiben, da diese Ereignisse eine negative ID haben und in der Tabelle TAB_EVENTS gar nicht vorkommen. In der Kalenderansicht bleiben sie jedoch an der neuen Stelle stehen und springen erst nach erneutem Laden der Seite an ihre alte Position zurück - das ist nicht so schön.

Besser ist es, für diese Ereignisse im PL/SQL Code einen Fehler auszulösen. Das kann übrigens in der Praxis auch für andere Ereignisse erforderlich sein - schließlich mag es auch in der Realität verschiebbare und nicht verschiebbare Ereignisse geben. Im folgenden wird bei einem negativen "Primärschlüsselwert" ein Fehler ausgelöst - natürlich kann man das auch anhand des Inhalts einer Tabellenspalte tun.

begin
  if :APEX$PK_VALUE < 0 then
    raise_application_error(-20612, 'Cannot reschedule generated events');
  else 
    update tab_events set 
      start_date = to_date(:APEX$NEW_START_DATE, 'YYYYMMDDHH24MISS'),
      end_date =   to_date(:APEX$NEW_END_DATE,   'YYYYMMDDHH24MISS')
    where id = :APEX$PK_VALUE;
  end if;
end;

Wenn Sie die Seite nun neu starten, können Sie die Ereignisse der Tabelle TAB_EVENTS wie vorher verschieben, bei den generierten Ereignissen erhalten Sie nun dagegen eine Fehlermeldung.

Drag & Drop für ein generiertes Ereignis löst einen Fehler aus

Abbildung 7: Drag & Drop für ein generiertes Ereignis löst einen Fehler aus

Für den Endanwender ist die Fehlermeldung, die da präsentiert wird, nicht so schön. Eine ORA-Fehlernummer ist für den Entwickler hilfreich, der Endbenutzer soll sie aber nicht sehen. Hier hilft uns das APEX-Errorhandling weiter, welches schon vor geraumer Zeit in APEX 4.1 eingeführt wurde. Erzeugen Sie zunächst eine Error-Handling-Funktion wie folgt.

create or replace function my_calendar_handler (
 p_error in apex_error.t_error 
) return apex_error.t_error_result is
  v_err apex_error.t_error_result;
begin
  v_err := apex_error.init_error_result ( p_error => p_error );
  if p_error.ora_sqlcode = -20612 then
    v_err.message := 'Ereignis kann nicht verschoben werden.';
  else
    v_err.message := p_error.message;
  end if;
  return v_err;
end;

Spielen Sie diese Funktion (zum Beispiel mit dem SQL Workshop) in Ihr Datenbankschema ein und hinterlegen Sie sie in den Seitenattributen als Error-Handler.

PL/SQL Error-Handling Funktion für die Seite festlegen

Abbildung 8: PL/SQL Error-Handling Funktion für die Seite festlegen

Starten Sie die Seite dann neu. Nun wird eine andere Fehlermeldung präsentiert.

Anwenderfreundliche Fehlermeldung bei ungültigem für Drag & Drop

Abbildung 9: Anwenderfreundliche Fehlermeldung bei ungültigem für Drag & Drop

Fazit

Mit APEX 5.0 lassen sich Ereignisdaten mit sehr wenig Aufwand als Kalenderansicht visualisieren. Nutzt man in der SQL-Abfrage, welche dem Kalender zugrundeliegt, den Funktionsumfang der Datenbank voll aus, so ist weit mehr möglich, als das einfache Selektieren von Daten. Fortgeschrittene Funktionen wie Drag & Drop, was vor einigen Jahren noch massiven Aufwand bedeutet hätte, ist in APEX 5.0 mit wenigen Mausklicks und PL/SQL-Codezeilen erledigt.

Im zweiten Teil des Tipps werden wir dann näher auf die Javascript-API von jQuery FullCalendar eingehen und vorstellen, wie man eine Kalenderregion komplett manuell erstellen und so über die Möglichkeiten von APEX hinausgehen kann.

Zurück zur Community-Seite