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
| Aspect | Fiori Elements | Freestyle Fiori |
|---|---|---|
| Effort de développement | Faible (1-2 jours) | Élevé (1-2 semaines) |
| Flexibilité UI | Limitée (Templates) | Illimitée |
| Effort de maintenance | Minimal | Continu |
| Courbe d’apprentissage | Annotations CDS | SAPUI5/JavaScript |
| Cohérence UX | Automatiquement conforme SAP | À assurer manuellement |
| Mises à jour | Fournies par SAP | Autonomes |
| Débogage | Plus 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
| Template | Description | Application typique |
|---|---|---|
| List Report | Table avec filtres et actions | Vues de données maîtres |
| Object Page | Vue détaillée avec facettes | Édition d’enregistrement unique |
| Analytical List Page | Combinaison de graphiques et table | Reporting, tableaux de bord |
| Worklist | Liste orientée tâches | Approbations, tâches |
| Overview Page | Tableau de bord basé sur des tuiles | Vues de gestion |
| Form Object Page | Vue axée sur les formulaires | Saisie de données |
Exemple de code Fiori Elements
Vue CDS Projection avec annotations UI :
@EndUserText.label: 'Commande - Projection"@Metadata.allowExtensions: truedefine 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: #COREannotate 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ère | Justification |
|---|---|
| ✅ Opérations CRUD standard | List Report + Object Page parfaitement adaptés |
| ✅ Développement rapide requis | Facteur 5-10x plus rapide que Freestyle |
| ✅ UX standard SAP souhaitée | Automatiquement Fiori Design Guidelines |
| ✅ Peu d’expertise UI dans l’équipe | Pas de connaissances JavaScript nécessaires |
| ✅ Maintenabilité à long terme importante | Mises à jour SAP automatiquement intégrées |
| ✅ Applications transactionnelles (RAP) | Intégration parfaite avec RAP |
| ✅ Applications analytiques avec graphiques standard | Utiliser Analytical List Page |
Freestyle Fiori recommandé
| Critère | Justification |
|---|---|
| ✅ UI hautement individualisée | Pas de limites de template |
| ✅ Visualisations personnalisées | Graphiques, diagrammes, cartes propres |
| ✅ Modèles d’interaction complexes | Drag & Drop, Wizards, Multi-Step |
| ✅ Bibliothèques tierces nécessaires | Intégration de composants externes |
| ✅ Design au pixel près requis | Contrôle complet du layout |
| ✅ Éléments de gamification | Animations, mécaniques de jeu |
| ✅ Exigences Offline-First | Logique 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’extension | Description | Effort |
|---|---|---|
| Header Extension | Contenu d’en-tête personnalisé | Faible |
| Footer Extension | Actions personnalisées dans le footer | Faible |
| Custom Column | Colonne propre avec renderer personnalisé | Moyen |
| Custom Section | Section propre dans Object Page | Moyen |
| Controller Extension | Override de méthodes de controller | Élevé |
| Building Block | Composants 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
-
Vitesse de développement
- Jusqu’à 80% de code en moins
- Pas de développement JavaScript
- Patterns standard immédiatement disponibles
-
Maintenabilité
- SAP fournit les mises à jour automatiquement
- Conformité d’accessibilité garantie
- Optimisations de performances incluses
-
Cohérence
- Automatiquement Fiori Design Guidelines
- UX uniforme sur toutes les applications
- Mobile-ready sans effort supplémentaire
-
Intégration avec RAP
- Connexion transparente au backend
- Draft Handling prêt à l’emploi
- Validations et actions automatiquement disponibles
Fiori Elements : Inconvénients
-
Flexibilité limitée
- Uniquement des templates prédéfinis
- Layouts personnalisés difficiles à réaliser
- Interactions complexes impossibles
-
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
-
Courbe d’apprentissage pour les annotations
- Nombreuses annotations à apprendre
- Documentation parfois lacunaire
- Essais-erreurs dans des scénarios complexes
Freestyle Fiori : Avantages
-
Contrôle complet
- Chaque élément UI personnalisable individuellement
- Interactions complexes possibles
- Designs au pixel près réalisables
-
Intégration de tierces parties
- Bibliothèques externes intégrables (Charts, Maps, etc.)
- Composants personnalisés réutilisables
- Pas de limites du framework
-
Débogage
- Code propre plus facile à déboguer
- Support complet des DevTools du navigateur
- Sources d’erreurs claires
Freestyle Fiori : Inconvénients
-
Effort de développement élevé
- 5-10x plus de code que Fiori Elements
- Expertise JavaScript/TypeScript nécessaire
- Temps de développement plus longs
-
Effort de maintenance
- Mises à jour à intégrer manuellement
- Accessibilité à assurer soi-même
- Optimisation des performances à assumer soi-même
-
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: #COREannotate 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 :
| Étape | Description |
|---|---|
| 1. Analyse | Quelles fonctionnalités sont standard vs. personnalisées ? |
| 2. Backend RAP | Migrer le backend vers RAP |
| 3. Annotations | Créer des annotations UI pour fonctionnalités standard |
| 4. Extensions personnalisées | Implémenter les fonctionnalités non standard comme extensions |
| 5. Migration | Migrer progressivement, template par template |
De Fiori Elements vers Freestyle
Rarement nécessaire, mais possible si les exigences augmentent fortement :
| Étape | Description |
|---|---|
| 1. Export XML | Exporter les vues XML générées comme base |
| 2. Controller | Reprendre la logique de controller des extensions |
| 3. Refactoring | Supprimer 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 :
- SAP Fiori Elements : Créer une UI sans code
- Tutoriel RAP Partie 1 : Première application Fiori
- Bases RAP : RESTful ABAP Programming
- Annotations CDS en détail