Fiori Elements vs. Freestyle Fiori : Quelle approche UI pour votre projet ?

Catégorie
UI
Publié
Auteur
Johannes

La question Fiori Elements ou Freestyle Fiori ? préoccupe de nombreux développeurs UI dans l’environnement SAP. Les deux approches ont leur place - mais quand chacune est-elle la bonne ? Cet article fournit un guide de décision fondé avec des exemples de code concrets et une matrice de décision claire.

Vue d’ensemble : Les deux mondes du développement Fiori

┌────────────────────────────────────────────────────────────────────┐
│ Développement UI SAP Fiori │
├────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────┐ ┌─────────────────────────────┐ │
│ │ Fiori Elements │ │ Freestyle Fiori │ │
│ │ (Basé annotations) │ │ (SAPUI5 Custom) │ │
│ ├─────────────────────────┤ ├─────────────────────────────┤ │
│ │ • UI automatique │ │ • Contrôle UI complet │ │
│ │ • Annotations CDS │ │ • Vues XML + Controller │ │
│ │ • Pas de JavaScript │ │ • JavaScript/TypeScript │ │
│ │ • Templates (List, OP) │ │ • Composants personnalisés │ │
│ │ • Mises à jour SAP incl.│ │ • Maintenance propre │ │
│ └─────────────────────────┘ └─────────────────────────────┘ │
│ │
│ Effort: ●○○○○ Effort: ●●●●● │
│ Flexibilité: ●●○○○ Flexibilité: ●●●●● │
│ │
└────────────────────────────────────────────────────────────────────┘

Comparaison rapide

AspectFiori ElementsFreestyle Fiori
Effort de développementFaible (1-2 jours)Élevé (1-2 semaines)
Flexibilité UILimitée (Templates)Illimitée
Effort de maintenanceMinimalContinu
Courbe d’apprentissageAnnotations CDSSAPUI5/JavaScript
Cohérence UXAutomatiquement conforme SAPÀ assurer manuellement
Mises à jourFournies par SAPAutonomes
DébogagePlus difficile (Framework)Plus facile (code propre)

Qu’est-ce que Fiori Elements ?

Fiori Elements est l’approche de SAP pour le développement UI déclaratif. Au lieu d’écrire du code UI, vous définissez l’interface par des Annotations dans le modèle de données CDS.

Comment fonctionne Fiori Elements

┌─────────────────────────────────────────────────────────────────┐
│ Fiori Elements │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Vue CDS + Annotations │
│ │ │
│ ▼ │
│ ┌───────────────────┐ │
│ │ Fiori Elements │ ──▶ Génération UI automatique │
│ │ Runtime │ │
│ └───────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────┐ │
│ │ Application Fiori prête │ │
│ │ • List Report │ │
│ │ • Object Page │ │
│ │ • Filtres, Actions, Navigation │ │
│ └───────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

Templates Fiori Elements disponibles

TemplateDescriptionApplication typique
List ReportTable avec filtres et actionsVues de données maîtres
Object PageVue détaillée avec facettesÉdition d’enregistrement unique
Analytical List PageCombinaison de graphiques et tableReporting, tableaux de bord
WorklistListe orientée tâchesApprobations, tâches
Overview PageTableau de bord basé sur des tuilesVues de gestion
Form Object PageVue axée sur les formulairesSaisie de données

Exemple de code Fiori Elements

Vue CDS Projection avec annotations UI :

@EndUserText.label: 'Commande - Projection"
@Metadata.allowExtensions: true
define root view entity ZC_ORDER
provider contract transactional_query
as projection on ZI_ORDER
{
key OrderId,
CustomerId,
OrderDate,
TotalAmount,
Currency,
Status,
/* Associations */
_Customer,
_Items
}

Metadata Extension (fichier .ddlx séparé) :

@Metadata.layer: #CORE
annotate view ZC_ORDER with
{
/* Informations d'en-tête */
@UI.headerInfo: {
typeName: 'Commande',
typeNamePlural: 'Commandes',
title: { value: 'OrderId' },
description: { value: '_Customer.CustomerName' }
}
/* Facets pour Object Page */
@UI.facet: [
{
id: 'OrderHeader',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Données de commande',
position: 10
},
{
id: 'OrderItems',
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
label: 'Positions',
position: 20,
targetElement: '_Items"
}
]
/* Annotations de champs */
@UI.lineItem: [{ position: 10, importance: #HIGH }]
@UI.identification: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
OrderId;
@UI.lineItem: [{ position: 20, importance: #HIGH }]
@UI.identification: [{ position: 20 }]
@UI.selectionField: [{ position: 20 }]
CustomerId;
@UI.lineItem: [{ position: 30 }]
@UI.identification: [{ position: 30 }]
OrderDate;
@UI.lineItem: [{ position: 40, criticality: 'StatusCriticality' }]
@UI.identification: [{ position: 40 }]
Status;
@UI.lineItem: [{ position: 50 }]
@UI.identification: [{ position: 50 }]
@Semantics.amount.currencyCode: 'Currency"
TotalAmount;
}

Résultat : Une application complète List Report + Object Page sans une seule ligne de JavaScript !


Qu’est-ce que Freestyle Fiori ?

Freestyle Fiori signifie le développement manuel avec le framework SAPUI5. Vous avez un contrôle total sur chaque aspect de l’interface utilisateur.

Comment fonctionne Freestyle Fiori

┌─────────────────────────────────────────────────────────────────┐
│ Freestyle Fiori │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ Vues XML │ │ Controllers │ │ Modèles │ │
│ │ (Layout) │ │ (JavaScript) │ │ (Données) │ │
│ └───────┬────────┘ └───────┬────────┘ └───────┬────────┘ │
│ │ │ │ │
│ └────────────────────┼────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Application Fiori personnalisée │ │
│ │ • Composants propres │ │
│ │ • Layouts personnalisés │ │
│ │ • Contrôle JavaScript complet │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

Exemple de code Freestyle Fiori

manifest.json (extrait) :

{
"sap.app": {
"id": "com.mycompany.orderapp",
"type": "application",
"title": "Gérer les commandes",
"dataSources": {
"mainService": {
"uri": "/sap/opu/odata4/sap/zapi_order/srvd_a2x/sap/zui_order/0001/",
"type": "OData",
"settings": {
"odataVersion": "4.0"
}
}
}
}
}

Vue (XML) :

<mvc:View
controllerName="com.mycompany.orderapp.controller.OrderList"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
xmlns:f="sap.f"
xmlns:core="sap.ui.core">
<f:DynamicPage id="orderPage">
<f:title>
<f:DynamicPageTitle>
<f:heading>
<Title text="Commandes"/>
</f:heading>
<f:actions>
<Button
text="Nouvelle commande"
type="Emphasized"
press=".onCreateOrder"/>
<Button
text="Exporter"
icon="sap-icon://excel-attachment"
press=".onExport"/>
</f:actions>
</f:DynamicPageTitle>
</f:title>
<f:header>
<f:DynamicPageHeader>
<f:content>
<FlexBox wrap="Wrap">
<Input
id="searchField"
placeholder="Rechercher une commande..."
liveChange=".onSearch"
width="300px"/>
<Select
id="statusFilter"
change=".onStatusFilterChange"
items="{/StatusOptions}">
<core:Item key="{Key}" text="{Text}"/>
</Select>
<DateRangeSelection
id="dateFilter"
change=".onDateFilterChange"/>
</FlexBox>
</f:content>
</f:DynamicPageHeader>
</f:header>
<f:content>
<Table
id="orderTable"
items="{/Orders}"
growing="true"
growingThreshold="50"
mode="MultiSelect"
selectionChange=".onSelectionChange">
<headerToolbar>
<OverflowToolbar>
<ToolbarSpacer/>
<Button
text="Supprimer"
icon="sap-icon://delete"
enabled="{= ${/SelectedCount} > 0}"
press=".onDeleteSelected"/>
</OverflowToolbar>
</headerToolbar>
<columns>
<Column width="10em">
<Text text="Numéro de commande"/>
</Column>
<Column width="15em">
<Text text="Client"/>
</Column>
<Column width="10em">
<Text text="Date"/>
</Column>
<Column width="8em" hAlign="End">
<Text text="Montant"/>
</Column>
<Column width="10em">
<Text text="Statut"/>
</Column>
</columns>
<items>
<ColumnListItem
type="Navigation"
press=".onOrderPress">
<cells>
<ObjectIdentifier
title="{OrderId}"
text="{OrderType}"/>
<Text text="{CustomerName}"/>
<Text text="{
path: 'OrderDate',
type: 'sap.ui.model.type.Date',
formatOptions: { style: 'medium' }
}"/>
<ObjectNumber
number="{
path: 'TotalAmount',
type: 'sap.ui.model.type.Currency',
formatOptions: { showMeasure: false }
}"
unit="{Currency}"/>
<ObjectStatus
text="{StatusText}"
state="{= ${Status} === 'COMPLETE' ? 'Success' : ${Status} === 'CANCELED' ? 'Error' : 'Warning' }"/>
</cells>
</ColumnListItem>
</items>
</Table>
</f:content>
</f:DynamicPage>
</mvc:View>

Controller (JavaScript) :

sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/model/json/JSONModel",
"sap/ui/model/Filter",
"sap/ui/model/FilterOperator",
"sap/m/MessageBox",
"sap/ui/export/Spreadsheet"
], function(Controller, JSONModel, Filter, FilterOperator, MessageBox, Spreadsheet) {
"use strict";
return Controller.extend("com.mycompany.orderapp.controller.OrderList", {
onInit: function() {
// Modèle de vue local pour l'état UI
var oViewModel = new JSONModel({
SelectedCount: 0,
StatusOptions: [
{ Key: "", Text: "Tous les statuts" },
{ Key: "NEW", Text: "Nouveau" },
{ Key: "INPROCESS", Text: "En cours" },
{ Key: "COMPLETE", Text: "Terminé" },
{ Key: "CANCELED", Text: "Annulé" }
]
});
this.getView().setModel(oViewModel);
},
onSearch: function(oEvent) {
var sQuery = oEvent.getParameter("newValue");
var oTable = this.byId("orderTable");
var oBinding = oTable.getBinding("items");
var aFilters = [];
if (sQuery) {
aFilters.push(new Filter({
filters: [
new Filter("OrderId", FilterOperator.Contains, sQuery),
new Filter("CustomerName", FilterOperator.Contains, sQuery)
],
and: false
}));
}
// Combiner avec le filtre de statut
this._applyFilters(aFilters);
},
onStatusFilterChange: function(oEvent) {
var sStatus = oEvent.getParameter("selectedItem").getKey();
this._sCurrentStatus = sStatus;
this._applyFilters();
},
onDateFilterChange: function(oEvent) {
var oDateRange = oEvent.getSource();
this._oDateFrom = oDateRange.getDateValue();
this._oDateTo = oDateRange.getSecondDateValue();
this._applyFilters();
},
_applyFilters: function(aAdditionalFilters) {
var aFilters = aAdditionalFilters || [];
// Filtre de statut
if (this._sCurrentStatus) {
aFilters.push(new Filter("Status", FilterOperator.EQ, this._sCurrentStatus));
}
// Filtre de date
if (this._oDateFrom && this._oDateTo) {
aFilters.push(new Filter("OrderDate", FilterOperator.BT,
this._oDateFrom, this._oDateTo));
}
var oTable = this.byId("orderTable");
var oBinding = oTable.getBinding("items");
oBinding.filter(aFilters.length > 0 ? new Filter({
filters: aFilters,
and: true
}) : []);
},
onSelectionChange: function(oEvent) {
var iSelectedCount = oEvent.getSource().getSelectedItems().length;
this.getView().getModel().setProperty("/SelectedCount", iSelectedCount);
},
onCreateOrder: function() {
// Navigation vers la vue de création
var oRouter = this.getOwnerComponent().getRouter();
oRouter.navTo("orderCreate");
},
onOrderPress: function(oEvent) {
// Navigation vers la vue détaillée
var oItem = oEvent.getSource();
var sOrderId = oItem.getBindingContext().getProperty("OrderId");
var oRouter = this.getOwnerComponent().getRouter();
oRouter.navTo("orderDetail", {
orderId: sOrderId
});
},
onDeleteSelected: function() {
var oTable = this.byId("orderTable");
var aSelectedItems = oTable.getSelectedItems();
MessageBox.confirm(
"Voulez-vous vraiment supprimer " + aSelectedItems.length + " commande(s) ?",
{
title: "Confirmer la suppression",
onClose: function(sAction) {
if (sAction === MessageBox.Action.OK) {
this._deleteOrders(aSelectedItems);
}
}.bind(this)
}
);
},
_deleteOrders: function(aItems) {
// Appels de suppression OData
var oModel = this.getView().getModel("mainService");
aItems.forEach(function(oItem) {
var sPath = oItem.getBindingContext().getPath();
oModel.remove(sPath, {
success: function() {
// Supprimé avec succès
},
error: function(oError) {
MessageBox.error("Erreur lors de la suppression: " + oError.message);
}
});
});
},
onExport: function() {
var oTable = this.byId("orderTable");
var oBinding = oTable.getBinding("items");
var oSpreadsheet = new Spreadsheet({
workbook: {
columns: [
{ label: "Numéro de commande", property: "OrderId" },
{ label: "Client", property: "CustomerName" },
{ label: "Date", property: "OrderDate", type: "Date" },
{ label: "Montant", property: "TotalAmount", type: "Number" },
{ label: "Devise", property: "Currency" },
{ label: "Statut", property: "StatusText" }
]
},
dataSource: oBinding,
fileName: "Commandes.xlsx"
});
oSpreadsheet.build();
}
});
});

Comparaison : Nettement plus de code, mais aussi nettement plus de contrôle sur chaque aspect de l’UI !


Matrice de décision : Quand quelle approche ?

Fiori Elements recommandé

CritèreJustification
✅ Opérations CRUD standardList Report + Object Page parfaitement adaptés
✅ Développement rapide requisFacteur 5-10x plus rapide que Freestyle
✅ UX standard SAP souhaitéeAutomatiquement Fiori Design Guidelines
✅ Peu d’expertise UI dans l’équipePas de connaissances JavaScript nécessaires
✅ Maintenabilité à long terme importanteMises à jour SAP automatiquement intégrées
✅ Applications transactionnelles (RAP)Intégration parfaite avec RAP
✅ Applications analytiques avec graphiques standardUtiliser Analytical List Page

Freestyle Fiori recommandé

CritèreJustification
✅ UI hautement individualiséePas de limites de template
✅ Visualisations personnaliséesGraphiques, diagrammes, cartes propres
✅ Modèles d’interaction complexesDrag & Drop, Wizards, Multi-Step
✅ Bibliothèques tierces nécessairesIntégration de composants externes
✅ Design au pixel près requisContrôle complet du layout
✅ Éléments de gamificationAnimations, mécaniques de jeu
✅ Exigences Offline-FirstLogique offline complète implémentable

Arbre de décision

Départ: Nouvelle application Fiori requise
┌──────────────────────┐
│ L'exigence UI peut-elle│
│ être réalisée avec des │
│ templates ? │
└─────────┬────────────┘
┌────────┴────────┐
│ │
▼ ▼
OUI NON
│ │
▼ ▼
┌───────────────┐ ┌────────────────┐
│ L'application │ │ → FREESTYLE │
│ nécessite-t- │ │ FIORI │
│ elle une │ └────────────────┘
│ logique │
│ personnalisée │
│ complexe ? │
└──────┬────────┘
┌────┴────┐
│ │
▼ ▼
OUI NON
│ │
▼ ▼
┌─────────────────┐ ┌────────────────────┐
│ La logique peut-│ │ → FIORI ELEMENTS │
│ elle être │ │ (Purement │
│ implémentée en │ │ déclaratif) │
│ ABAP (RAP) ? │ └────────────────────┘
└────────┬────────┘
┌────┴────┐
│ │
▼ ▼
OUI NON
│ │
▼ ▼
┌──────────────────┐ ┌────────────────────┐
│ → FIORI ELEMENTS │ │ → FREESTYLE FIORI │
│ avec backend │ │ ou Hybride │
│ RAP │ └────────────────────┘
└──────────────────┘

Approche hybride : Fiori Elements + Extensions personnalisées

Dans de nombreux cas, une approche hybride est le meilleur compromis : Fiori Elements comme base avec des extensions personnalisées ciblées.

Possibilités d’extension dans Fiori Elements

Type d’extensionDescriptionEffort
Header ExtensionContenu d’en-tête personnaliséFaible
Footer ExtensionActions personnalisées dans le footerFaible
Custom ColumnColonne propre avec renderer personnaliséMoyen
Custom SectionSection propre dans Object PageMoyen
Controller ExtensionOverride de méthodes de controllerÉlevé
Building BlockComposants UI réutilisablesÉlevé

Exemple : Extension de section personnalisée

manifest.json (extrait) :

{
"sap.ui5": {
"extends": {
"extensions": {
"sap.ui.controllerExtensions": {
"sap.fe.templates.ObjectPage.ObjectPageController": {
"controllerName": "com.mycompany.orderapp.ext.ObjectPageExt"
}
}
}
},
"routing": {
"targets": {
"OrderObjectPage": {
"options": {
"settings": {
"content": {
"body": {
"sections": {
"CustomSection": {
"template": "com.mycompany.orderapp.ext.CustomSection",
"title": "Suivi de livraison",
"position": {
"anchor": "OrderItems",
"placement": "After"
}
}
}
}
}
}
}
}
}
}
}
}

Fragment de section personnalisée :

<core:FragmentDefinition
xmlns="sap.m"
xmlns:core="sap.ui.core"
xmlns:macros="sap.fe.macros">
<VBox class="sapUiSmallMargin">
<Title text="Suivi d'envoi"/>
<!-- Composant de carte personnalisé -->
<FlexBox height="300px" width="100%">
<core:HTML content="{= ${DeliveryMapHtml} }"/>
</FlexBox>
<ProgressIndicator
percentValue="{= ${DeliveryProgress} }"
displayValue="{= ${DeliveryStatus} }"
state="{= ${DeliveryProgress} === 100 ? 'Success' : 'Information' }"
showValue="true"/>
<HBox class="sapUiTinyMarginTop">
<Button
text="Détails de suivi"
type="Transparent"
icon="sap-icon://map"
press=".extension.com.mycompany.orderapp.ext.ObjectPageExt.onShowTrackingDetails"/>
</HBox>
</VBox>
</core:FragmentDefinition>

Extension de controller :

sap.ui.define([
"sap/ui/core/mvc/ControllerExtension",
"sap/m/MessageBox"
], function(ControllerExtension, MessageBox) {
"use strict";
return ControllerExtension.extend("com.mycompany.orderapp.ext.ObjectPageExt", {
// Override: Appelé lors du chargement de l'Object Page
override: {
onPageReady: function(mParameters) {
// Initialisation personnalisée
this._loadDeliveryTracking();
}
},
// Méthode personnalisée pour les détails de suivi
onShowTrackingDetails: function(oEvent) {
var oContext = this.base.getView().getBindingContext();
var sTrackingNumber = oContext.getProperty("TrackingNumber");
// Ouvrir le dialogue personnalisé
if (!this._oTrackingDialog) {
this._oTrackingDialog = sap.ui.xmlfragment(
"com.mycompany.orderapp.ext.TrackingDialog",
this
);
this.base.getView().addDependent(this._oTrackingDialog);
}
this._oTrackingDialog.open();
},
_loadDeliveryTracking: function() {
// Appel API personnalisé pour données de suivi
var oContext = this.base.getView().getBindingContext();
if (!oContext) return;
var sOrderId = oContext.getProperty("OrderId");
// Exemple: API de suivi externe
fetch("/api/tracking/" + sOrderId)
.then(function(response) { return response.json(); })
.then(function(data) {
// Mettre à jour le modèle avec les données de suivi
var oModel = this.base.getView().getModel();
oModel.setProperty(oContext.getPath() + "/DeliveryProgress", data.progress);
oModel.setProperty(oContext.getPath() + "/DeliveryStatus", data.status);
}.bind(this));
}
});
});

Avantages et inconvénients en détail

Fiori Elements : Avantages

  1. Vitesse de développement

    • Jusqu’à 80% de code en moins
    • Pas de développement JavaScript
    • Patterns standard immédiatement disponibles
  2. Maintenabilité

    • SAP fournit les mises à jour automatiquement
    • Conformité d’accessibilité garantie
    • Optimisations de performances incluses
  3. Cohérence

    • Automatiquement Fiori Design Guidelines
    • UX uniforme sur toutes les applications
    • Mobile-ready sans effort supplémentaire
  4. Intégration avec RAP

    • Connexion transparente au backend
    • Draft Handling prêt à l’emploi
    • Validations et actions automatiquement disponibles

Fiori Elements : Inconvénients

  1. Flexibilité limitée

    • Uniquement des templates prédéfinis
    • Layouts personnalisés difficiles à réaliser
    • Interactions complexes impossibles
  2. Défis de débogage

    • Code généré par le framework difficile à déboguer
    • Erreurs d’annotations difficiles à trouver
    • Moins de contrôle direct
  3. Courbe d’apprentissage pour les annotations

    • Nombreuses annotations à apprendre
    • Documentation parfois lacunaire
    • Essais-erreurs dans des scénarios complexes

Freestyle Fiori : Avantages

  1. Contrôle complet

    • Chaque élément UI personnalisable individuellement
    • Interactions complexes possibles
    • Designs au pixel près réalisables
  2. Intégration de tierces parties

    • Bibliothèques externes intégrables (Charts, Maps, etc.)
    • Composants personnalisés réutilisables
    • Pas de limites du framework
  3. Débogage

    • Code propre plus facile à déboguer
    • Support complet des DevTools du navigateur
    • Sources d’erreurs claires

Freestyle Fiori : Inconvénients

  1. Effort de développement élevé

    • 5-10x plus de code que Fiori Elements
    • Expertise JavaScript/TypeScript nécessaire
    • Temps de développement plus longs
  2. Effort de maintenance

    • Mises à jour à intégrer manuellement
    • Accessibilité à assurer soi-même
    • Optimisation des performances à assumer soi-même
  3. Risque d’incohérence

    • Incohérences UX possibles
    • Guidelines Fiori à respecter manuellement
    • Coordination d’équipe plus importante

Comparaison de code : Même fonctionnalité

Exigence : Liste de commandes avec filtre et navigation

Fiori Elements (env. 50 lignes d’annotations) :

@Metadata.layer: #CORE
annotate view ZC_ORDER with
{
@UI.headerInfo: {
typeName: 'Commande',
typeNamePlural: 'Commandes',
title: { value: 'OrderId' }
}
@UI.lineItem: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
OrderId;
@UI.lineItem: [{ position: 20 }]
@UI.selectionField: [{ position: 20 }]
CustomerId;
@UI.lineItem: [{ position: 30 }]
OrderDate;
@UI.lineItem: [{ position: 40, criticality: 'StatusCriticality' }]
@UI.selectionField: [{ position: 30 }]
Status;
}

Freestyle Fiori (env. 250 lignes de code) :

  • manifest.json : 50 lignes
  • View.xml : 80 lignes
  • Controller.js : 120 lignes

Conclusion : Pour les scénarios CRUD standard, Fiori Elements est nettement plus efficace.


Exemples pratiques : Quand quelle approche ?

Exemple 1 : Maintenance de données maîtres (→ Fiori Elements)

Exigence : CRUD pour données client maîtres avec adresse et contacts

Pourquoi Fiori Elements :

  • CRUD standard avec List Report + Object Page
  • Entités enfants (adresses, contacts) comme facettes
  • Validations via RAP
  • Draft Handling pour formulaires longs

Exemple 2 : Tableau de bord avec graphiques personnalisés (→ Freestyle)

Exigence : Tableau de bord de gestion avec visualisations interactives

Pourquoi Freestyle :

  • Visualisations D3.js ou Highcharts personnalisées
  • Drag & Drop pour arrangement de widgets
  • Mises à jour en temps réel via WebSocket
  • Interactions de filtres complexes

Exemple 3 : Workflow d’approbation (→ Fiori Elements)

Exigence : Processus d’approbation pour demandes d’achat

Pourquoi Fiori Elements :

  • Template Worklist idéal pour listes de tâches
  • Actions (Approuver, Rejeter) faciles à définir
  • Navigation standard entre tâches
  • Mobile-ready sans effort supplémentaire

Exemple 4 : Configurateur de produit (→ Freestyle)

Exigence : Configurateur de produit 3D interactif

Pourquoi Freestyle :

  • Rendu 3D avec Three.js
  • Interactions complexes (rotation, zoom)
  • Calcul de prix dynamique en frontend
  • Logique de validation personnalisée

Exemple 5 : Hybride - Gestion des commandes avec suivi

Exigence : Gestion de commandes standard + suivi de livraison avec carte

Solution : Fiori Elements + Extension personnalisée

  • List Report et Object Page comme base
  • Section personnalisée avec intégration de carte
  • Extension de controller pour API de suivi

Migration entre les approches

De Freestyle vers Fiori Elements

Dans certains cas, une migration de Freestyle vers Fiori Elements peut être judicieuse :

ÉtapeDescription
1. AnalyseQuelles fonctionnalités sont standard vs. personnalisées ?
2. Backend RAPMigrer le backend vers RAP
3. AnnotationsCréer des annotations UI pour fonctionnalités standard
4. Extensions personnaliséesImplémenter les fonctionnalités non standard comme extensions
5. MigrationMigrer progressivement, template par template

De Fiori Elements vers Freestyle

Rarement nécessaire, mais possible si les exigences augmentent fortement :

ÉtapeDescription
1. Export XMLExporter les vues XML générées comme base
2. ControllerReprendre la logique de controller des extensions
3. RefactoringSupprimer les dépendances du framework
4. Modèle personnaliséAdapter la connexion OData

Bonnes pratiques

Pour Fiori Elements

À FAIREÀ NE PAS FAIRE
✅ Annotations dans fichier .ddlx séparé❌ Trop d’annotations inline dans CDS
✅ Utiliser RAP pour logique complexe❌ Mettre la logique dans les extensions UI
✅ Utiliser les templates standard❌ Effectuer des personnalisations excessives
✅ Metadata Extensions pour la lisibilité❌ Tout écrire dans un seul fichier
✅ Building Blocks pour réutilisation❌ Implémenter chaque extension individuellement

Pour Freestyle Fiori

À FAIREÀ NE PAS FAIRE
✅ Suivre les Fiori Design Guidelines❌ Inventer un design complètement propre
✅ Utiliser les contrôles sap.ui.core❌ HTML natif sans bonne raison
✅ Utiliser le routage pour la navigation❌ Construire sa propre navigation
✅ Modèles pour binding de données❌ Manipulation DOM directe
✅ Garder la logique de controller petite❌ Tout mettre dans un seul controller

Conclusion : La bonne approche pour votre projet

Choisissez Fiori Elements si :

  • Vous construisez des applications CRUD standard
  • Vous devez être productif rapidement
  • Vous avez peu d’expertise frontend
  • Vous priorisez la maintenabilité à long terme

Choisissez Freestyle Fiori si :

  • Vous avez besoin d’UI hautement individualisées
  • Vous intégrez des visualisations personnalisées ou des bibliothèques tierces
  • Vous implémentez des modèles d’interaction complexes
  • Vous avez besoin d’un contrôle total sur chaque aspect

Choisissez Hybride si :

  • 80% standard, 20% personnalisé
  • Des sections ou colonnes spéciales sont nécessaires
  • Vous voulez combiner les avantages des deux mondes

En pratique : 80-90% des applications transactionnelles SAP peuvent être efficacement réalisées avec Fiori Elements. L’approche hybride couvre 5-8% supplémentaires. Ce n’est que pour des exigences vraiment spéciales que Freestyle Fiori pur est la bonne voie.


Voir aussi :