RAP - Feature Control
In diesem Artikel geht es um die Feature Control, einen Mechanismus, um dynamisch Funktionen im RAP anhand des Zustands des Objekts zu aktivieren oder zu deaktivieren.
Inhaltsverzeichnis
Mit Feature Control können die verschiedenen Felder und Eigenschaften zur Laufzeit noch einmal angepasst werden, um so zum Beispiel Aktionen zu aktivieren oder zu deaktivieren. In diesem Artikel erfährst du mehr, wie du diese Funktion nutzt, um damit mehr Flexibilität in dein Datenmodell zu bekommen.
Einleitung
Diese Funktion wird vom RAP Framework zur Verfügung gestellt, ist aber kein "Must-Have", sondern kann optional zu den bestehenden Funktionen eingesetzt werden. Im aktuellen Stand unseres Beispiels haben wir bisher diese Funktion noch nicht eingesetzt und werden dies mit diesem Artikel einmal probieren. Feature Control kann auf Felder eingesetzt werden, um gewisse Eigenschaften zu beeinflussen, auf Standardoperationen (z.B.: Update, Delete) und auf Aktionen, um sie zu aktivieren oder zu deaktivieren.
Am Ende musst du entscheiden wie du das Feature implementierst:
- Instanzbasiertes Feature ("features:instance") - Dir stehen die Daten der einzelnen Instanz zur Verfügung, es wird pro Instanz entschieden, wie mit dem Feature umgegangen wird.
- Globales Feature ("features:global") - Es gibt keinen Zugriff auf die Daten, aber es wird einmalig entschieden, ob das Feature genutzt werden kann oder nicht.
Instanz Feature
Schauen wir uns nun einmal die instanzbasierten Features an und wie wir sie ordentlich nutzen können. Dazu erweitern wir die Aktion "fillEmptyStreets". Diese Aktion ist aktuell immer aktiv, wenn ein Datensatz gewählt wird. Wir möchten diese Aktion aber nun umstellen, sodass der Button nur gedrückt werden kann, wenn keine Straße im Datensatz befüllt ist. Dazu musst du nun das entsprechende Feature in der Definition aufnehmen:
action ( features : instance ) fillEmptyStreets result [1] $self;
Nachdem du die Aktion erweitert hast, kannst du Verhaltensdefinition nun aktivieren und wirst eine Warnung auf Ebene der Definition sehen. Nun muss noch die Operation implementiert werden, dazu kannst du einfach auf den Namen der Entität gehen und mit STRG + 1 die nötige Methode implementieren lassen:
Nachdem die Methode "get_instance_feature" nun implementiert wurde, schauen wir uns einmal die Signatur der Methode an, um zu schauen mit welchen Daten wir rechnen können:
Wieder einmal stehen uns mehr Parameter zur Verfügung, als eigentlich in der Signatur definiert wurden. Schauen wir uns einmal die wichtigsten Parameter etwas genauer an:
- KEYS - Übergabe alle Instanzen die geprüft werden sollen. Lädt die Liste zum ersten Mal, dann werden alle anzuzeigenden Datensätze geladen.
- REQUESTED FEATURES - Struktur, bei der die zu prüfenden Features markiert sind. Wird für die unterschiedlichen Prüfungen herangezogen.
- RESULT - Ergebnis der Entitäten bei denen das Feature deaktiviert werden soll
Nachdem nun die Grundlagen definiert wurden und die Importparameter der Methode klar sind, können wir nun mit der Implementierung beginnen. Dazu prüfen wir im ersten Schritt, welches Feature gerade überprüft werden soll. Dann lesen wir die passenden Daten dazu nach und übernehmen die einzelnen Datensätze in die Ergebnistabelle:
IF requested_features-%action-fillEmptyStreets = if_abap_behv=>mk-on.
READ ENTITIES OF ZBS_I_RAPPartner IN LOCAL MODE
ENTITY Partner FIELDS ( Street ) WITH CORRESPONDING #( keys )
RESULT DATA(lt_partner_data).
LOOP AT lt_partner_data INTO DATA(ls_partner).
DATA(ld_deactivate) = COND #(
WHEN ls_partner-Street IS INITIAL THEN if_abap_behv=>mk-off
ELSE if_abap_behv=>mk-on
).
INSERT VALUE #(
partnernumber = ls_partner-PartnerNumber
%action-fillemptystreets = ld_deactivate
) INTO TABLE result.
ENDLOOP.
ENDIF.
Hinweis: Die Features sind standardmäßig alle aktiviert und müssen für die nicht passenden Entitäten nun deaktiviert werden. Demnach kann nach Optimierung des Codes oben das Beispiel auch wie folgt aussehen:
IF requested_features-%action-fillEmptyStreets = if_abap_behv=>mk-on.
READ ENTITIES OF ZBS_I_RAPPartner IN LOCAL MODE
ENTITY Partner FIELDS ( Street ) WITH CORRESPONDING #( keys )
RESULT DATA(lt_partner_data).
LOOP AT lt_partner_data INTO DATA(ls_partner) WHERE Street IS NOT INITIAL.
INSERT VALUE #(
partnernumber = ls_partner-PartnerNumber
%action-fillemptystreets = if_abap_behv=>mk-on
) INTO TABLE result.
ENDLOOP.
ENDIF.
Schauen wir nun das Ergebnis einmal in der App an, wenn wir einen Datensatz markieren, der bereits eine hinterlegte Straße hat, dann wird der Button nun deaktiviert:
Markieren wir nun einen Datensatz beim dem keine Straße gepflegt ist, wird der Button aktiviert und wir können die Aktion in RAP nutzen:
Global Feature
Im nächsten Beispiel wollen wir einmal ein Feature auf globaler Ebene einschränken und zwar das Löschen von Datensätzen über die App. Aktuell ist das Feature für jeden freigeschaltet, der die App nutzen kann. Dazu erweitern wir die Operation in der Verhaltensdefinition wie schon zuvor für das Instanz-Feature.
delete ( features : global );
Für die Implementierung eines globalen Features muss die Methode "get_global_features" implementiert werden. Wie bereits vorher beschrieben, gibt es hier keine Übergabe der Keys von außen. Die Ableitung der verschiedenen Features muss über andere Kriterien erfolgen. Das folgende Beispiel zeigt eine Beispiel-Implementierung, um die Löschfunktion nur bestimmten Usern zur Verfügung zu stellen:
IF requested_features-%delete = if_abap_behv=>mk-on.
DATA(ld_deactivate) = COND #(
WHEN cl_abap_context_info=>get_user_alias( ) = '<USER>' THEN if_abap_behv=>mk-off
ELSE if_abap_behv=>mk-on
).
result-%delete = ld_deactivate.
ENDIF.
Dabei solltest du wieder beachten, dass du das Feature dort deaktivieren musst, wo es nicht benötigt wird. Die Rückgabe ist dieses Mal eine Struktur, da wir hier das gesamte Feature (Löschen) bearbeiten.
Fazit
Einzelne Features im RAP Business Objekt zu aktivieren und zu deaktivieren, sollte nun kein Problem für dich sein. Du weißt, wie du ein Feature pro Datensatz und auf gesamter Ebene deaktivierst und das die Features zu Beginn an immer aktiviert sind.