MVC architecture
Every SAPUI5 app separates three pieces: the view (XML, defines the layout), the controller (JavaScript, holds the logic) and the model (the data, typically an ODataModel or a JSONModel). This separation lets you test the logic without touching the UI.
<mvc:View controllerName="com.dev.app.controller.ContractList" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"> <Table id="contractTable" items="{/Contracts}"> <columns> <Column><Text text="ID" /></Column> <Column><Text text="Manager" /></Column> </columns> <items> <ColumnListItem press="onContractPress"> <cells> <Text text="{ContractId}" /> <Text text="{ContractManager}" /> </cells> </ColumnListItem> </items> </Table> </mvc:View>
The controller
The controller receives events from the view and decides what to do: navigate, call the model, open a dialog. It always extends sap.ui.core.mvc.Controller.
sap.ui.define([ "sap/ui/core/mvc/Controller", "sap/m/MessageToast" ], function (Controller, MessageToast) { "use strict"; return Controller.extend("com.dev.app.controller.ContractList", { onContractPress: function (oEvent) { const oContext = oEvent.getSource().getBindingContext(); const sId = oContext.getProperty("ContractId"); MessageToast.show(`Opening contract ${sId}`); this.getOwnerComponent().getRouter() .navTo("detail", { contractId: sId }); } }); });
The OData model
The ODataModel connects the app to the SAP backend (a CDS view exposed as a service, typically via RAP). The {/Contracts} binding in the view resolves automatically against this entity.
const oModel = new ODataModel("/sap/opu/odata4/sap/zcontract_srv/srvd/sap/zui_contract/0001/", { synchronizationMode: "None", operationMode: "Server", autoExpandSelect: true }); this.setModel(oModel);
Fiori Elements: when not to write the view by hand
When the app follows a standard pattern (List Report + Object Page), Fiori Elements generates the UI from the CDS view's annotations, with no XML or controller to write. It's only customised via extensions (metadata extensions, controller extensions) when the standard doesn't cover a specific case.