使用控制器扩展
学习目标
应用 SAP Fiori elements 提供的控制器扩展来添加您的自定义 JavaScript 代码。
函数导入
开放数据协议(OData)包含标准 CRUD(Create, Read, Update 和 Delete)操作,它们映射到 HTTP 方法 POST, GET, PUT/MERGE 和 DELETE。
此外,OData 还支持更多服务操作(函数导入),对于任何无法映射到标准 CRUD 操作的内容,可以通过 HTTP 方法 GET 或 POST 调用这些操作。您可以在后端实现这些额外的服务操作。
在本培训中,您使用 CAP 作为后端,并将在 CAP 数据模型中创建一个函数导入。
当您向 CAP 数据模型添加函数导入的定义时,它就会成为服务元数据的一部分。您可以在 $metadata 文档中找到它。

上面的屏幕截图显示,函数导入与服务的实体集一起被添加到服务容器中。
在同一个 $metadata 文档中,您可以找到该函数导入的 API。

一旦函数导入成为 $metadata 的一部分,就可以在客户端于您的 SAP Fiori elements 应用中使用它。
控制器扩展
SAP Fiori elements for OData V4 提供了一组控制器扩展。它们公开了您可以覆盖的方法。请在 控制器扩展的 API 参考 中查看可用控制器扩展的列表。
例如,类 sap.fe.core.controllerextensions.EditFlow 提供了进入 SAP Fiori elements 应用编辑流程的钩子。
在本课中,您将使用 sap.fe.core.controllerextensions.Routing 控制器扩展的 onAfterBinding 方法来调用函数导入。然后您将评估其返回值,并在恰当的时机(即在页面已绑定但尚未渲染之后)显示消息条(如有必要)。
向 Display Customers 应用的对象页添加消息条
在您的 Display Customers 应用中,您可能希望在存在状态为 New 的预订时通知用户。为此,您将在对象页上的 Own Bookings 表上方显示相应的消息。
在前一个练习中,您已经创建了一个自定义区段并向其中添加了 Table 构建块。现在,您将向该表添加一个消息条。您还将看到向整个对象页添加消息的选项。
任务流程
显示客户预订的表使用分页来限制数据交换负载:仅加载前十个行。这意味着您无法在 UI 端分析所有预订;这应在后端完成。为此,您将在后端创建一个函数导入。
您首先将使用 Page Map 向 Display Customers 应用添加一个控制器扩展。
接下来,您将使用一个新函数扩展您的 CAP 服务。它将在后端检查所选客户是否存在状态为 New 的预订。
之后,您将能够使用控制器扩展在前端调用此函数。如果存在状态为“new”的预订,将在表上方显示一个警告消息条。
最后,如果存在任何状态为 New 的预订,您将向整个对象页添加一条信息消息。
前提条件
您已完成单元 发现 SAP Fiori Elements for OData V4 编程模型的灵活性(课程:使用构建块)中的练习 在 Display Customers 应用中使用 Table 构建块创建表。或者,您可以检出其解决方案分支:solution/add-table-building-block。
观看模拟并执行步骤
本练习包含一个展示所有步骤的模拟。您可以使用自己的试用账户跟随该模拟进行操作。
Exercise:Start Exercise(SAP 官方交互式练习)
步骤
向您的应用添加一个控制器扩展。
打开 Display Customers 应用的对象页并切换到 SAP Business Application Studio。
打开
*webapp*文件夹并选择 Show Page Map>Object Page>Add Controller Extension。添加 PassengerOPExtend 作为控制器名称。
您现在已添加一个新的控制器扩展。
使用一个新函数扩展您的 CAP 服务。
打开
*schema.cds*并将以下代码片段粘贴到文件中:
type BookingData: { HasNewBookings: Boolean }
这将在您的数据模型中添加一个新类型 BookingData。
2. 打开 *travel-service.cds* 并向其中添加以下函数定义:
// Function import used in Controller Extension 'PassengerOPExtend.js' to calculate booking data function getBookingDataOfPassenger(CustomerID: String) returns my.BookingData;
这将添加一个新函数 getBookingDataOfPassenger。
3. 打开 *travel-service.js* 并添加以下代码片段:
/** * Function import handler: getBookingDataOfPassenger * @param CustomerID * @returns BookingData */ this.on('getBookingDataOfPassenger', async (req) => { const { CustomerID } = req.data const allCustomerBookings = await SELECT `BookingStatus_code as status`.from (Booking) .where `to_Customer_CustomerID = ${CustomerID}` const bookingData = { HasNewBookings: false } bookingData.HasNewBookings = allCustomerBookings.some((booking) => { return booking.status === 'N'; }) return bookingData });
您已添加 getBookingDataOfPassenger 函数的实现。
它以 CustomerID 作为参数,并按 Customer 检查数据库中状态为 New 的预订。
3. 向控制器扩展添加一个函数。
打开控制器扩展文件
*PassengerOPExtend.controller.js*并添加以下代码片段:
sap.ui.define(['sap/ui/core/mvc/ControllerExtension',"sap/ui/core/message/Message","sap/ui/core/MessageType", ], function (ControllerExtension, Message, MessageType) { 'use strict'; return ControllerExtension.extend('sap.fe.cap.customer.ext.controller.PassengerOPExtend', { // this section allows to extend lifecycle hooks or hooks provided by Fiori elements override: { /** * Called when a controller is instantiated and its View controls (if available) are already created. * Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization. * @memberOf sap.fe.cap.customer.ext.controller.PassengerOPExtend */ onInit: function () { // you can access the Fiori elements extensionAPI via this.base.getExtensionAPI var oModel = this.base.getExtensionAPI().getModel(); }, routing: { onAfterBinding: async function (oBindingContext) { } } } }); });
您已添加 routing 对象的 onAfterBinding 函数(类 sap.fe.core.controllerControllerextensions.Routing)。
2. 将以下代码片段添加到 onAfterBinding 函数中:
onAfterBinding: async function (oBindingContext) { const oExtensionAPI = this.base.getExtensionAPI(), oModel = oExtensionAPI.getModel(), sFunctionName = "getBookingDataOfPassenger", oFunction = oModel.bindContext(`/${sFunctionName}(...)`), oBookingTableAPI = oExtensionAPI.byId("fe::CustomSubSection::Bookings--OwnBookingsTable"), oWarningMessage = new Message({ type: MessageType.Warning, message: await oExtensionAPI.getModel("i18n").getResourceBundle().getText("bookingsNew") }), oInfoMessage = new Message({ type: MessageType.Info, message: await oExtensionAPI.getModel("i18n").getResourceBundle().getText("bookingsAttention") }); // Request OData function with current CustomerID const oCustomer = await oBindingContext.requestObject(oBindingContext.getPath()); oFunction.setParameter("CustomerID", oCustomer.CustomerID); await oFunction.execute(); const oContext = oFunction.getBoundContext(); if (this.message !== undefined) { oBookingTableAPI.removeMessage(this.message); } if (oContext.getProperty("HasNewBookings")) { this.message = oBookingTableAPI.addMessage(oWarningMessage); oExtensionAPI.showMessages([oInfoMessage]); } }
您已向 onAfterBinding 添加了一些代码。通过这段代码,您在 SAPUI5 OData V4 模型 中访问了后端函数 getBookingDataOfPassenger,获取了表构建块的表 API,并创建了一条警告消息。
您还创建了一条类型为 Info 的消息。如果后端函数的 HasNewBookings 参数为 true,则会使用对象页控制器的 extensionAPI 将该信息消息添加到整个对象页。
3. 在文件资源管理器中打开 *i18n* 文件并添加以下代码片段:
#XMSG: Warning message on object page bookingsNew=There are new bookings that have not yet been accepted. #XMSG: Info message on object page bookingsAttention=Some bookings require your attention
您刚刚已将警告消息和信息消息文本添加到 *i18n.properties* 文件中。
4. 切换到应用窗口。您可以看到 Theresia Buccholm 的预订显示了警告消息,因为其中一些预订具有 New 状态。您还可以在对象页标题中看到一条信息消息。
结果
在本练习中,您添加了两个消息条:一个用于表构建块,一个用于整个对象页。为此,您在 CAP 服务中创建并实现了一个函数,用于检查给定客户是否存在状态为 New 的预订。在前端(控制器扩展中),您实现了函数调用并在需要时添加了消息。
注意
您可以在以下位置找到本练习的解决方案: GitHub 。
解决方案分支是 solution/add-message-strips 。
您可以在以下位置找到该分支与前一个分支的直接比较链接: Github 。