Simple Table Maintenance in SAP Fiori Using UI5 Smart Controls

Estimated read time 13 min read

1. What Is a Classic Maintenance View/Table in SAP GUI?

In the SAP GUI world, creating a maintenance view (or table maintenance dialog) is straightforward using transaction-based tools such as SM30. You can generate a maintenance view for a custom table, enabling easy data creation, updates, and deletions. This approach requires minimal coding—SAP generates the necessary screens, logic, and button controls automatically.

Such classic maintenance views are often used by functional teams or administrators to manage configuration tables, text tables, or other small datasets. The big advantage is that it’s a “no-frills” approach — it just works. However, as organizations move to SAP S/4HANA and Fiori, many are looking for a modern UI that is responsive, mobile-friendly, and integrated with Fiori Launchpad.

2. What Are the Current Solutions for It in Fiori with and without RAP?

When transitioning to SAP Fiori, you can no longer rely on SM30-like screens for table maintenance in a straightforward way. Instead you have workarounds like object page editing: Embed an edit-enabled table on an object page to mimic SM30. While this can work, it’s often not the most straightforward approach if your goal is simply to maintain a table of records (see blog post Generating SAP Fiori Table Maintenance Dialogs in SAP S/4HANA 2021.)

3. What Makes My Solution Better?

The solution outlined here is designed with simplicity in mind and takes advantage of the following:

OData V2: Avoid mandatory draft handling and simplify immediate data saves.Smart Controls: Declarative UI annotations determine how fields are displayed and edited, minimizing custom coding for the UI layout.Freestyle UI5 App: This approach gives you flexibility to add custom buttons, event handlers, or logic but still using the annotations from the backend

Essentially, you get a classic “table maintenance” style application but with a modern, responsive Fiori interface, plus the flexibility to extend it if your requirements grow.

4. How Does It Work? (With Code Samples)

Below is an overview of the key pieces in this project. The full sample is available on GitHub: https://github.com/marianfoo/fiori-table-maintenance.

4.1 Main View (XML)

The main view is a simple UI5 XML view containing a SmartFilterBar and a SmartTable. With the “editable” property set to true and editTogglable also enabled, the table allows inline editing. We also have buttons for refreshing and saving changes.

 

 

<mvc:View controllerName=”com.starwars.fighter.controller.MainView”
xmlns:mvc=”sap.ui.core.mvc”
xmlns=”sap.m”
xmlns:table=”sap.ui.table”
xmlns:f=”sap.f”
xmlns:smarttable=”sap.ui.comp.smarttable”
xmlns:smartvariants=”sap.ui.comp.smartvariants”
xmlns:smartfilterbar=”sap.ui.comp.smartfilterbar”
xmlns:app=”http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1″
xmlns:core=”sap.ui.core”>
<Page id=”page” title=”{i18n>title}”>
<f:DynamicPage id=”dynamicPageId” headerExpanded=”true” toggleHeaderOnTitleClick=”true”>
<f:title>
<f:DynamicPageTitle>
<f:heading>
<smartvariants:SmartVariantManagement
id=”svm”
persistencyKey=”StarWarsFighterVariants”
showShare=”true”/>
</f:heading>
</f:DynamicPageTitle>
</f:title>

<f:header>
<f:DynamicPageHeader pinnable=”true”>
<smartfilterbar:SmartFilterBar
id=”smartFilterBar”
entitySet=”StarWarsFighter”
persistencyKey=”StarWarsFighterFilter”
useToolbar=”false”>
</smartfilterbar:SmartFilterBar>
</f:DynamicPageHeader>
</f:header>

<f:content>
<smarttable:SmartTable
id=”smartTable”
entitySet=”StarWarsFighter”
smartFilterId=”smartFilterBar”
smartVariant=”svm”
tableType=”Table”
enableExport=”true”
editable=”true”
editTogglable=”true”
app:useSmartToggle=”true”
app:useSmartField=”true”
beforeExport=”.onBeforeExport”
useVariantManagement=”true”
useTablePersonalisation=”true”
header=”Star Wars Fighters”
showRowCount=”true”
enableAutoColumnWidth=”true”
enableAutoBinding=”true”
persistencyKey=”StarWarsFighterSmartTable”
fieldChange=”.onFieldChange”
class=”sapUiResponsiveMargin”>

<smarttable:customToolbar>
<OverflowToolbar>
<ToolbarSpacer />
<Button text=”Refresh Table” type=”Emphasized” press=”.onRefreshTable”/>
<Button text=”Save Changes” type=”Emphasized” press=”.onSubmitChanges”/>
</OverflowToolbar>
</smarttable:customToolbar>
</smarttable:SmartTable>
</f:content>
</f:DynamicPage>
</Page>
</mvc:View>

 

 

 

4.2 TypeScript Controller

The controller handles basic logic: refreshing the table binding and submitting changes. Notice the use of model.submitChanges() to save modifications to the server.
With the onFieldChange method everytime a user changes a field (and leaves the field or pressing enter) the changes are submitted to the backend.
You can also use the button to only send the changes to the backend when it is pressed.
The UI5 Framework is smart enough to notice only the changes and create batch requests for it.

 

 

import SmartTable from ‘sap/ui/comp/smarttable/SmartTable’;
import Controller from ‘sap/ui/core/mvc/Controller’;
import ODataModel from ‘sap/ui/model/odata/v2/ODataModel’;
import Table from ‘sap/ui/table/Table’;

/**
* @namespace com.starwars.fighter.controller
*/
export default class MainView extends Controller {
public onInit(): void {
// Initialization logic (if needed)
}

public onRefreshTable(): void {
const smartTable = this.byId(‘smartTable’) as SmartTable;
const innerTable = smartTable.getTable() as Table;
innerTable.getBinding(‘rows’).refresh();
}

public onFieldChange(): void {
const smartTable = this.byId(‘smartTable’) as SmartTable;
const model = smartTable.getModel() as ODataModel;
// Immediately submit changes whenever a field is changed
model.submitChanges();
}

public async onSubmitChanges(): Promise {
const smartTable = this.byId(‘smartTable’) as SmartTable;
const model = smartTable.getModel() as ODataModel;
model.submitChanges();
}
}

 

 

4.3 Annotations (annotations.cds)

UI Annotations let Smart Controls know which fields to display by default, which fields are editable, and how to label them. I use standard annotations like LineItems and SelectionFields.
In CAP i can use the “Computed” Annotation to make a field in the table not editable.
I made only the status field editable.

 

 

annotate sw.StarWarsFighter with {
name @title: ‘Fighter Name’ .Computed;
manufacturer @title: ‘Manufacturer’ .Computed;
);

 

 

4.4 CAP Schema

The CAP schema (CDS) defines the entities (StarWarsFighter and FighterStatus) and their properties. CAP automatically generates an OData service based on this definition.
With the CAP Plugin @cap-js-community/odata-v2-adapter i can automatically create the V2 Service i need in my app.

 

 

namespace my.starwars;

entity FighterStatus {
key code: String;
name: String;
description: String;
isOperational: Boolean;

fighters: Association to many StarWarsFighter on fighters.status = $self;
}

entity StarWarsFighter {
key id: String(10);
name: String;
manufacturer: String;
model: String;
fighterCategory: String;
builtAt: Timestamp;
height: Decimal(5,2);
weight: Decimal(7,2);
length: Decimal(5,2);
width: Decimal(5,2);
crewSize: Integer;
passengerCapacity: Integer;
propulsion: String;
maxAtmosphericSpeed: String;
maxAcceleration: String;
hyperdriveClass: String;
laserCannons: Integer;
protonTorpedoCapacity: Integer;
additionalWeapons: String;

status: Association to FighterStatus;
}

 

 

 

4.5 Sample Data

Finally, you can load some sample CSV data into the StarWarsFighter entity. Here’s a snippet:

 

 

id,name,manufacturer,model,fighterCategory,builtAt,height,weight,length,width,crewSize,passengerCapacity,propulsion,maxAtmosphericSpeed,maxAcceleration,hyperdriveClass,laserCannons,protonTorpedoCapacity,additionalWeapons,status_code
SF001,X-wing,Incom Corporation,T-65B,Assault,2020-01-15T10:00:00Z,2.4,10000,12.5,11.76,1,0,Twin ion engines,1050 km/h,3100 G,1.0 HCR,4,6,Deflector shields,AVAILABLE
SF002,TIE Fighter,Sienar Fleet Systems,TIE/ln,Interceptor,2020-02-20T08:30:00Z,7.5,6300,6.3,6.4,1,0,Twin ion engines,1200 km/h,4100 G,0,2,0,None,MISSION

 

 

With all these parts combined, you have a full CAP-based, OData V2 service that your UI5 application (featuring SmartTable) can consume. The end result is a modern UI for table maintenance with immediate saving, filter capabilities, sorting, and variant management—similar to the classic SM30 experience but Fiori-style.

Conclusion

Switching from the “classic” SAP GUI table maintenance to a Fiori-based solution doesn’t have to be complex. By using CAP/RAP Backend, a freestyle UI5 app, and OData V2 (plus UI annotations), you can quickly set up a user-friendly, fully responsive table maintenance application. You get instant saves without the overhead of drafts, plus the flexibility to adapt the UI to more complex scenarios if needed.

Check out the full source and try it out yourself on GitHub: https://github.com/marianfoo/fiori-table-maintenance.

Feel free to leave a comment or ask questions below if you have any feedback or want to share your experiences with table maintenance in Fiori!

 

​ 1. What Is a Classic Maintenance View/Table in SAP GUI?In the SAP GUI world, creating a maintenance view (or table maintenance dialog) is straightforward using transaction-based tools such as SM30. You can generate a maintenance view for a custom table, enabling easy data creation, updates, and deletions. This approach requires minimal coding—SAP generates the necessary screens, logic, and button controls automatically.Such classic maintenance views are often used by functional teams or administrators to manage configuration tables, text tables, or other small datasets. The big advantage is that it’s a “no-frills” approach — it just works. However, as organizations move to SAP S/4HANA and Fiori, many are looking for a modern UI that is responsive, mobile-friendly, and integrated with Fiori Launchpad.2. What Are the Current Solutions for It in Fiori with and without RAP?When transitioning to SAP Fiori, you can no longer rely on SM30-like screens for table maintenance in a straightforward way. Instead you have workarounds like object page editing: Embed an edit-enabled table on an object page to mimic SM30. While this can work, it’s often not the most straightforward approach if your goal is simply to maintain a table of records (see blog post Generating SAP Fiori Table Maintenance Dialogs in SAP S/4HANA 2021.)3. What Makes My Solution Better?The solution outlined here is designed with simplicity in mind and takes advantage of the following:OData V2: Avoid mandatory draft handling and simplify immediate data saves.Smart Controls: Declarative UI annotations determine how fields are displayed and edited, minimizing custom coding for the UI layout.Freestyle UI5 App: This approach gives you flexibility to add custom buttons, event handlers, or logic but still using the annotations from the backendEssentially, you get a classic “table maintenance” style application but with a modern, responsive Fiori interface, plus the flexibility to extend it if your requirements grow.4. How Does It Work? (With Code Samples)Below is an overview of the key pieces in this project. The full sample is available on GitHub: https://github.com/marianfoo/fiori-table-maintenance.4.1 Main View (XML)The main view is a simple UI5 XML view containing a SmartFilterBar and a SmartTable. With the “editable” property set to true and editTogglable also enabled, the table allows inline editing. We also have buttons for refreshing and saving changes.  <mvc:View controllerName=”com.starwars.fighter.controller.MainView”
xmlns:mvc=”sap.ui.core.mvc”
xmlns=”sap.m”
xmlns:table=”sap.ui.table”
xmlns:f=”sap.f”
xmlns:smarttable=”sap.ui.comp.smarttable”
xmlns:smartvariants=”sap.ui.comp.smartvariants”
xmlns:smartfilterbar=”sap.ui.comp.smartfilterbar”
xmlns:app=”http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1″
xmlns:core=”sap.ui.core”>
<Page id=”page” title=”{i18n>title}”>
<f:DynamicPage id=”dynamicPageId” headerExpanded=”true” toggleHeaderOnTitleClick=”true”>
<f:title>
<f:DynamicPageTitle>
<f:heading>
<smartvariants:SmartVariantManagement
id=”svm”
persistencyKey=”StarWarsFighterVariants”
showShare=”true”/>
</f:heading>
</f:DynamicPageTitle>
</f:title>

<f:header>
<f:DynamicPageHeader pinnable=”true”>
<smartfilterbar:SmartFilterBar
id=”smartFilterBar”
entitySet=”StarWarsFighter”
persistencyKey=”StarWarsFighterFilter”
useToolbar=”false”>
</smartfilterbar:SmartFilterBar>
</f:DynamicPageHeader>
</f:header>

<f:content>
<smarttable:SmartTable
id=”smartTable”
entitySet=”StarWarsFighter”
smartFilterId=”smartFilterBar”
smartVariant=”svm”
tableType=”Table”
enableExport=”true”
editable=”true”
editTogglable=”true”
app:useSmartToggle=”true”
app:useSmartField=”true”
beforeExport=”.onBeforeExport”
useVariantManagement=”true”
useTablePersonalisation=”true”
header=”Star Wars Fighters”
showRowCount=”true”
enableAutoColumnWidth=”true”
enableAutoBinding=”true”
persistencyKey=”StarWarsFighterSmartTable”
fieldChange=”.onFieldChange”
class=”sapUiResponsiveMargin”>

<smarttable:customToolbar>
<OverflowToolbar>
<ToolbarSpacer />
<Button text=”Refresh Table” type=”Emphasized” press=”.onRefreshTable”/>
<Button text=”Save Changes” type=”Emphasized” press=”.onSubmitChanges”/>
</OverflowToolbar>
</smarttable:customToolbar>
</smarttable:SmartTable>
</f:content>
</f:DynamicPage>
</Page>
</mvc:View>   4.2 TypeScript ControllerThe controller handles basic logic: refreshing the table binding and submitting changes. Notice the use of model.submitChanges() to save modifications to the server.With the onFieldChange method everytime a user changes a field (and leaves the field or pressing enter) the changes are submitted to the backend.You can also use the button to only send the changes to the backend when it is pressed.The UI5 Framework is smart enough to notice only the changes and create batch requests for it.  import SmartTable from ‘sap/ui/comp/smarttable/SmartTable’;
import Controller from ‘sap/ui/core/mvc/Controller’;
import ODataModel from ‘sap/ui/model/odata/v2/ODataModel’;
import Table from ‘sap/ui/table/Table’;

/**
* @namespace com.starwars.fighter.controller
*/
export default class MainView extends Controller {
public onInit(): void {
// Initialization logic (if needed)
}

public onRefreshTable(): void {
const smartTable = this.byId(‘smartTable’) as SmartTable;
const innerTable = smartTable.getTable() as Table;
innerTable.getBinding(‘rows’).refresh();
}

public onFieldChange(): void {
const smartTable = this.byId(‘smartTable’) as SmartTable;
const model = smartTable.getModel() as ODataModel;
// Immediately submit changes whenever a field is changed
model.submitChanges();
}

public async onSubmitChanges(): Promise {
const smartTable = this.byId(‘smartTable’) as SmartTable;
const model = smartTable.getModel() as ODataModel;
model.submitChanges();
}
}  4.3 Annotations (annotations.cds)UI Annotations let Smart Controls know which fields to display by default, which fields are editable, and how to label them. I use standard annotations like LineItems and SelectionFields.In CAP i can use the “Computed” Annotation to make a field in the table not editable.I made only the status field editable.  annotate sw.StarWarsFighter with {
name @title: ‘Fighter Name’ .Computed;
manufacturer @title: ‘Manufacturer’ .Computed;
);  4.4 CAP SchemaThe CAP schema (CDS) defines the entities (StarWarsFighter and FighterStatus) and their properties. CAP automatically generates an OData service based on this definition.With the CAP Plugin @cap-js-community/odata-v2-adapter i can automatically create the V2 Service i need in my app.  namespace my.starwars;

entity FighterStatus {
key code: String;
name: String;
description: String;
isOperational: Boolean;

fighters: Association to many StarWarsFighter on fighters.status = $self;
}

entity StarWarsFighter {
key id: String(10);
name: String;
manufacturer: String;
model: String;
fighterCategory: String;
builtAt: Timestamp;
height: Decimal(5,2);
weight: Decimal(7,2);
length: Decimal(5,2);
width: Decimal(5,2);
crewSize: Integer;
passengerCapacity: Integer;
propulsion: String;
maxAtmosphericSpeed: String;
maxAcceleration: String;
hyperdriveClass: String;
laserCannons: Integer;
protonTorpedoCapacity: Integer;
additionalWeapons: String;

status: Association to FighterStatus;
}   4.5 Sample DataFinally, you can load some sample CSV data into the StarWarsFighter entity. Here’s a snippet:  id,name,manufacturer,model,fighterCategory,builtAt,height,weight,length,width,crewSize,passengerCapacity,propulsion,maxAtmosphericSpeed,maxAcceleration,hyperdriveClass,laserCannons,protonTorpedoCapacity,additionalWeapons,status_code
SF001,X-wing,Incom Corporation,T-65B,Assault,2020-01-15T10:00:00Z,2.4,10000,12.5,11.76,1,0,Twin ion engines,1050 km/h,3100 G,1.0 HCR,4,6,Deflector shields,AVAILABLE
SF002,TIE Fighter,Sienar Fleet Systems,TIE/ln,Interceptor,2020-02-20T08:30:00Z,7.5,6300,6.3,6.4,1,0,Twin ion engines,1200 km/h,4100 G,0,2,0,None,MISSION
…  With all these parts combined, you have a full CAP-based, OData V2 service that your UI5 application (featuring SmartTable) can consume. The end result is a modern UI for table maintenance with immediate saving, filter capabilities, sorting, and variant management—similar to the classic SM30 experience but Fiori-style.ConclusionSwitching from the “classic” SAP GUI table maintenance to a Fiori-based solution doesn’t have to be complex. By using CAP/RAP Backend, a freestyle UI5 app, and OData V2 (plus UI annotations), you can quickly set up a user-friendly, fully responsive table maintenance application. You get instant saves without the overhead of drafts, plus the flexibility to adapt the UI to more complex scenarios if needed.Check out the full source and try it out yourself on GitHub: https://github.com/marianfoo/fiori-table-maintenance.Feel free to leave a comment or ask questions below if you have any feedback or want to share your experiences with table maintenance in Fiori!   Read More Technology Blogs by Members articles 

#SAP

#SAPTechnologyblog

You May Also Like

More From Author