使用控制器扩展

学习目标

  • 应用 SAP Fiori elements 提供的控制器扩展来添加您的自定义 JavaScript 代码。

函数导入

开放数据协议(OData)包含标准 CRUDCreate, Read, UpdateDelete)操作,它们映射到 HTTP 方法 POST, GET, PUT/MERGEDELETE

此外,OData 还支持更多服务操作(函数导入),对于任何无法映射到标准 CRUD 操作的内容,可以通过 HTTP 方法 GETPOST 调用这些操作。您可以在后端实现这些额外的服务操作。

在本培训中,您使用 CAP 作为后端,并将在 CAP 数据模型中创建一个函数导入。

当您向 CAP 数据模型添加函数导入的定义时,它就会成为服务元数据的一部分。您可以在 $metadata 文档中找到它。

突出显示 FunctionImport 的示例代码

上面的屏幕截图显示,函数导入与服务的实体集一起被添加到服务容器中。

在同一个 $metadata 文档中,您可以找到该函数导入的 API。

函数导入 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

观看模拟并执行步骤

本练习包含一个展示所有步骤的模拟。您可以使用自己的试用账户跟随该模拟进行操作。

ExerciseStart Exercise(SAP 官方交互式练习)

步骤

  1. 向您的应用添加一个控制器扩展。

  2. 打开 Display Customers 应用的对象页并切换到 SAP Business Application Studio。

  3. 打开 *webapp* 文件夹并选择 Show Page Map>Object Page>Add Controller Extension

  4. 添加 PassengerOPExtend 作为控制器名称。

  5. 您现在已添加一个新的控制器扩展。

  6. 使用一个新函数扩展您的 CAP 服务。

  7. 打开 *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. 向控制器扩展添加一个函数。

  1. 打开控制器扩展文件 *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 。