在这一步中,我们将用一个自定义控件来扩展SAPUI5的功能。我们希望对显示在详细信息页面上的产品进行评级,因此我们使用SAPUI5扩展机制创建了多个标准控件的组合,并添加了一些连接代码,使它们能够很好地一起工作。这样,我们可以在整个应用程序中重用控件,并将所有相关的功能保存在一个模块中。
webapp/control/ProductRating.js (New)
sap.ui.define([
"sap/ui/core/Control"
], function (Control) {
"use strict";
return Control.extend("sap.ui.demo.walkthrough.control.ProductRating", {
metadata : {
},
init : function () {
},
renderer : function (oRM, oControl) {
}
});
});
我们创建一个新的文件夹控件和一个文件将保存我们的新控件的productratings .js。与我们的控制器和视图一样,自定义控件从SAPUI5基对象继承了公共控件功能,对于控件来说,这是通过扩展基类sap.ui.core.Control来完成的。
自定义控件是可以在应用程序中很容易创建的小型重用组件。由于它们的特性,它们有时也被称为“记事本”或“动态”控件。自定义控件是一个JavaScript对象,它有两个特殊的部分(数据和视图)和许多实现控件功能的方法。
元数据部分定义了数据结构,从而定义了控件的API。通过这些关于控件属性、事件和聚合的元信息,SAPUI5自动创建setter和getter方法以及其他可以在应用程序中调用的便利函数。
渲染器定义了HTML结构,当控件在视图中实例化时,该结构将被添加到应用程序的DOM树中。它通常最初由SAPUI5的核心调用,在控件的属性发生改变时调用。呈现函数的参数oRM是SAPUI5呈现管理器,它可以用来向HTML页面编写字符串和控制属性。
init方法是一个特殊的函数,每当控件被实例化时,SAPUI5核心都会调用它。它可用于设置控件并准备显示其内容。
控件总是扩展sap.ui.core.Control并呈现自己。你也可以直接扩展sap.ui.core.Element或sap.ui.base.ManagedObject,如果你想重用SAPUI5的生命周期特性,包括未呈现的对象的数据绑定。请参考API参考来了解更多关于控件继承层次结构的信息。
webapp/control/ProductRating.js
sap.ui.define([
"sap/ui/core/Control",
"sap/m/RatingIndicator",
"sap/m/Label",
"sap/m/Button"
"RatingIndicator控件用于收集用户对产品的输入,一个标签显示进一步的信息,一个按钮将评级提交给应用程序以存储它。"
], function (Control, RatingIndicator, Label, Button){
"use strict";
return Control.extend("sap.ui.demo.walkthrough.control.ProductRating", {
metadata : {
properties : {
value: {type : "float", defaultValue : 0}
},
aggregations : {
_rating : {type : "sap.m.RatingIndicator", multiple: false, visibility : "hidden"},
_label : {type : "sap.m.Label", multiple: false, visibility : "hidden"},
_button : {type : "sap.m.Button", multiple: false, visibility : "hidden"}
},
events : {
change : {
parameters : {
value : {type : "int"}
}
}
}
},
init : function () {
this.setAggregation("_rating", new RatingIndicator({
value: this.getValue(),
iconSize: "2rem",
visualMode: "Half",
liveChange: this._onRate.bind(this) "liveChange"
}));
this.setAggregation("_label", new Label({
text: "{i18n>productRatingLabelInitial}"
}).addStyleClass("sapUiSmallMargin"));
this.setAggregation("_button", new Button({
text: "{i18n>productRatingButton}",
press: this._onSubmit.bind(this) " press"
}).addStyleClass("sapUiTinyMarginTopBottom"));
},
setValue: function (fValue) {
this.setProperty("value", fValue, true);
this.getAggregation("_rating").setValue(fValue);
},
reset: function () {
var oResourceBundle = this.getModel("i18n").getResourceBundle();
this.setValue(0);
this.getAggregation("_label").setDesign("Standard");
this.getAggregation("_rating").setEnabled(true);
this.getAggregation("_label").setText(oResourceBundle.getText("productRatingLabelInitial"));
this.getAggregation("_button").setEnabled(true);
},
_onRate : function (oEvent) {
var oRessourceBundle = this.getModel("i18n").getResourceBundle();
var fValue = oEvent.getParameter("value");
this.setProperty("value", fValue, true);
this.getAggregation("_label").setText(oRessourceBundle.getText("productRatingLabelIndicator", [fValue, oEvent.getSource().getMaxValue()]));
this.getAggregation("_label").setDesign("Bold");
},
_onSubmit : function (oEvent) {
var oResourceBundle = this.getModel("i18n").getResourceBundle();
this.getAggregation("_rating").setEnabled(false);
this.getAggregation("_label").setText(oResourceBundle.getText("productRatingLabelFinal"));
this.getAggregation("_button").setEnabled(false);
this.fireEvent("change", {
value: this.getValue()
});
},
renderer : function (oRm, oControl) {
oRm.openStart("div", oControl);
oRm.class("myAppDemoWTProductRating");
oRm.openEnd();
oRm.renderControl(oControl.getAggregation("_rating"));
oRm.renderControl(oControl.getAggregation("_label"));
oRm.renderControl(oControl.getAggregation("_button"));
oRm.close("div");
}
});
});
现在,我们用所需的自定义功能增强了新的自定义控件。在本例中,我们希望创建一个交互式的产品评级,因此我们定义一个值并使用三个内部控件,这些控件自动更新显示。RatingIndicator控件用于收集用户对产品的输入,一个标签显示进一步的信息,一个按钮将评级提交给应用程序以存储它。
因此,在数据部分,我们定义了几个属性:
Value
我们定义一个控件属性值,该属性值将保存用户在评级中选择的值。这个属性的Getter和setter函数将自动创建,如果愿意,我们还可以将它绑定到XML视图中的数据模型的一个字段。
Aggregations
如第一段所述,我们需要三个内部控制来实现我们的评级功能。因此,通过将visibility属性设置为hidden,我们创建了三个隐藏聚合。
这样,我们可以在内部控件中使用视图中设置的模型,SAPUI5将负责生命周期管理,并在不再需要这些控件时销毁它们。聚合也可以用来保存控件数组,但我们只想在每个聚合中都有一个控件,因此需要通过将属性倍数设置为false来调整基数。
_rating: A
sap.m.RatingIndicator 用户输入控件
_label: A sap.m.Label to
显示额外的信息
_button: A sap.m.Button to
提交评级
注释
可以为控件定义聚合和关联。区别在于父控件和相关控件之间的关系:
聚合 aggregation是一种强关系,它还管理相关控件的生命周期,例如,当父控件被销毁时,相关控件也被销毁。此外,控件只能分配给一个单独的聚合,如果将其分配给第二个聚合,则将自动从先前的聚合中删除该控件。
关联是一种弱关联,它不管理生命周期,可以被定义多次。为了有明确的区别,关联只存储ID,而聚合存储对控件的直接引用。在这个例子中,我们没有指定关联,因为我们想让我们的内部控制由父方管理。
更改
我们指定了一个更改事件,当评级提交时,控件将触发该事件。它包含当前值作为事件参数。应用程序可以注册到这个事件并处理类似于“常规”SAPUI5控件的结果,后者实际上是类似于自定义控件构建的。
每当控件的一个新实例被实例化时,SAPUI5就会自动调用init函数,在这个函数中,我们设置了内部控件。我们实例化这三个控件,并通过调用从sap.ui.core.Control继承来的框架方法setAggregation将它们存储在内部聚合中。我们传递上面指定的内部聚合的名称和新的控件实例。我们指定了一些控件属性以使我们的自定义控件看起来更漂亮,并为评级注册了liveChange事件,为按钮注册了press事件。标签和按钮的初始文本来自我们的i18n模型。
现在让我们先忽略其他内部帮助函数和事件处理程序,然后定义我们的渲染器。在SAPUI5呈现管理器和作为引用传递的控件实例的帮助下,可以控件渲染HTML结构。我们将外部
setValue是一个被重写的setter。当在控制器中调用或定义时,SAPUI5将生成一个setter来更新属性值XML视图,但是我们还需要更新隐藏聚合中的内部评级控制,以正确地反映状态。同样,我们可以跳过SAPUI5的重新呈现,这通常是在控件上的属性被更改时触发的,通过调用setProperty方法以true作为第三个参数更新控件属性。
现在我们为内部评级控制定义事件处理程序。每次用户更改评级时都会调用它。rating控件的当前值可以从sap.m.RatingIndicator控件的事件参数值中读取。使用该值,我们调用重写的setter来更新控件状态,然后更新评级旁边的标签,以显示用户当前选择的值,并显示最大值。带有占位符值的字符串是从自动分配给控件的i18n模型中读取的。
接下来,我们有用于提交评级的评级按钮的按下处理程序。我们假设对产品进行评级是一次性操作,首先禁用评级和按钮,这样用户就不允许提交另一个评级。我们还会更新标签,显示“感谢您的评价!”,然后我们触发控件的change事件,并将当前值作为参数传入,以便侦听此事件的应用程序可以对评级交互作出反应。
我们定义了reset方法,以便能够将UI上的控件状态恢复到初始状态,以便用户可以再次提交评级。
webapp/view/Detail.view.xml
<mvc:View
controllerName="sap.ui.demo.walkthrough.controller.Detail"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
xmlns:wt="sap.ui.demo.walkthrough.control">
<Page
title="{i18n>detailPageTitle}"
showNavButton="true"
navButtonPress=".onNavBack">
<ObjectHeader
intro="{invoice>ShipperName}"
title="{invoice>ProductName}"/>
<wt:ProductRating id="rating" class="sapUiSmallMarginBeginEnd" change=".onRatingChange"/>
</Page>
</mvc:View>
在detail视图上定义了一个新的命名空间wt,这样我们就可以在视图中轻松地引用我们的自定义控件。的实例
ProductRating控件,并为更改事件注册一个事件处理程序。为了有一个合适的布局,我们还添加了一个边距样式类。
webapp/controller/Detail.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/routing/History",
"sap/m/MessageToast",
"sap/ui/core/UIComponent"
], function (Controller, History, MessageToast, UIComponent) {
"use strict";
return Controller.extend("sap.ui.demo.walkthrough.controller.Detail", {
…
_onObjectMatched: function (oEvent) { "_onObjectMatched ``````````````"
this.byId("rating").reset();
this.getView().bindElement({
path: "/" + oEvent.getParameter("arguments").invoicePath,
model: "invoice"
});
},
onNavBack: function () {
var oHistory = History.getInstance();
var sPreviousHash = oHistory.getPreviousHash();
if (sPreviousHash !== undefined) {
window.history.go(-1);
} else {
var oRouter = UIComponent.getRouterFor(this);
oRouter.navTo("overview", {}, true);
}
},
onRatingChange: function (oEvent) {
var fValue = oEvent.getParameter("value");
var oResourceBundle = this.getView().getModel("i18n").getResourceBundle();
MessageToast.show(oResourceBundle.getText("ratingConfirmation", [fValue]));
}
});
});
在Detail控制器中,我们将依赖项加载到sap.m.MessageToast,因为我们将只显示一条消息,而不是将评级发送到后端,以保持示例的简单性。事件处理程序onRatingChange读取评级提交时触发的定制更改事件的值。然后,我们显示一个带有MessageToast控件中的值的确认消息。
在onObjectMatched私有方法中,我们调用reset方法,使它能够在一个不同项目的详细视图显示时立即提交另一个评级。
webapp/css/style.css
.myAppDemoWTmyCustomButton.sapMBtn {
margin-right: 0.125rem;
}
.myAppDemoWTmyCustomText {
font-weight: bold;
}
/* ProductRating */
.myAppDemoWTProductRating {
padding: 0.75rem;
}
.myAppDemoWTProductRating .sapMRI {
vertical-align: initial;
}
为了布局控件,我们向根类添加一些填充,以使三个内部控件周围有一些空间,并覆盖RatingIndicator控件,使其与标签和按钮在一行中对齐。我们也可以在渲染器中使用更多的HTML,但这是最简单的方式,它将只应用于我们的自定义控件。但是,请注意,自定义控件在您的应用程序中,可能需要在SAPUI5未来版本的内部控件更改时进行调整。
webapp/i18n/i18n.properties
…
# Detail Page
detailPageTitle=Walkthrough - Details
ratingConfirmation=You have rated this product with {0} stars
# Product Rating
productRatingLabelInitial=Please rate this product
productRatingLabelIndicator=Your rating: {0} out of {1}
productRatingLabelFinal=Thank you for your rating!
productRatingButton=Rate
使用确认消息和我们在自定义控件中引用的字符串扩展资源包。我们现在可以用我们的全新控件在详细页面上评价产品。
约定
将自定义控件放到应用程序的控件文件夹中。
在这一步中,我们改进了应用程序的响应能力。SAPUI5应用程序可以在手机、平板电脑和桌面设备上运行,我们可以配置应用程序,以便在每个场景中充分利用屏幕属性。幸运的是,SAPUI5控件,比如sap.m.Table,已经提供了很多我们可以使用的特性。
webapp/view/InvoiceList.view.xml
<mvc:View
controllerName="sap.ui.demo.walkthrough.controller.InvoiceList"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc">
<Table
id="invoiceList"
class="sapUiResponsiveMargin"
width="auto"
items="{
path : 'invoice>/Invoices',
sorter : {
path : 'ShipperName',
group : true
}
}">
<headerToolbar>
<Toolbar>
<Title text="{i18n>invoiceListTitle}"/>
<ToolbarSpacer/>
<SearchField width="50%" search=".onFilterInvoices"/>
</Toolbar>
</headerToolbar>
"----------------------------------------------------------------------------------------------"
<columns>
<Column
hAlign="End"
minScreenWidth="Small"
demandPopin="true"
width="4em">
<Text text="{i18n>columnQuantity}"/>
</Column>
<Column>
<Text text="{i18n>columnName}"/>
</Column>
<Column
minScreenWidth="Small"
demandPopin="true">
<Text text="{i18n>columnStatus}"/>
</Column>
<Column
minScreenWidth="Tablet"
demandPopin="false">
<Text text="{i18n>columnSupplier}"/>
</Column>
<Column
hAlign="End">
<Text text="{i18n>columnPrice}"/>
</Column>
</columns>
<items>
"----------------------------------------------------------------------------------------"
<ColumnListItem
type="Navigation"
press=".onPress">
<cells>
<ObjectNumber number="{invoice>Quantity}" emphasized="false"/>
<ObjectIdentifier title="{invoice>ProductName}"/>
<Text text="{
path: 'invoice>Status',
formatter: '.formatter.statusText'
}"/>
<Text text="{invoice>ShipperName}"/>
<ObjectNumber
number="{
parts: [{path: 'invoice>ExtendedPrice'}, {path: 'view>/currency'}],
type: 'sap.ui.model.type.Currency',
formatOptions: {
showMeasure: false
}
}"
unit="{view>/currency}"
state="{= ${invoice>ExtendedPrice} > 50 ? 'Error' : 'Success' }"/>
</cells>
</ColumnListItem>
</items>
</Table>
</mvc:View>
只需替换标记,就可以用表交换与
。这个表有一个内置的响应功能,可以让我们的应用程序更灵活。表和列表共享相同的属性集,因此我们可以简单地重用它们和排序器。因为一个表的每一行都有多个单元格,所以我们必须为表定义列,并根据数据为这些列命名。我们在列聚合中添加了5个sap.m.Column控件,每个控件的配置都稍有不同:Quantity
该列将包含一个短数字,因此我们将对齐方式设置为End(在LTR语言中意味着“右”),并将宽度设置为4em,这对于列描述来说足够长了。我们使用sap.m.Text控件作为描述文本,该控件引用资源包的一个属性。我们将属性minScreenWidth设置为Small,表示这一列在手机上不那么重要。通过将demandPopin属性设置为true,我们将告诉表在主列下面显示这一列。
Name
我们的主列有一个相当大的宽度,以显示所有的细节。它将始终显示。
Status
状态不是那么重要,所以我们也可以通过设置minScreenWidth为small和demandPopin为true在小屏幕的name字段下面显示它
Supplier
我们通过设置minScreenWidth为Tablet和demandPopin为false来完全隐藏手机设备上的Supplier列。
Price
这一栏总是可见的,因为它包含了我们的发票价格。我们将不再使用以前的ObjectListItem,而是将信息拆分到与上面定义的列匹配的单元格上。因此,我们将其更改为具有相同属性的columnlisttitem控件,但现在使用了单元格聚合。这里我们创建了五个控件来显示我们的数据:
Quantity
绑定到数据字段的简单的sap.m.ObjectNumber控件。
Name
一个sap.m.ObjectIdentifier控件用于指定名称。
Status
一个具有与以前相同的格式化程序的sap. m.t文本控件。
Supplier
一个简单的sap.m.Text控件。
Price
一个ObjectNumber控件,具有与前面步骤中的属性number和numberUnit相同的格式化程序。
现在我们已经响应地定义了我们的表,当我们减少浏览器的屏幕大小时,可以看到结果。供应商栏不显示手机大小,数量和状态两栏将显示在名称下面。
webapp/i18n/i18n.properties
...
# Invoice List
invoiceListTitle=Invoices
invoiceStatusA=New
invoiceStatusB=In Progress
invoiceStatusC=Done
columnQuantity=Quantity
columnName=Name
columnSupplier=Supplier
columnStatus=Status
columnPrice=Price
# Detail Page
...
我们将列名和属性标题添加到i18n文件中。当我们缩小浏览器的屏幕尺寸或在一个小设备上打开应用程序时,我们可以看到结果。
约定
为手机、平板电脑和桌面设备的不同屏幕尺寸优化应用程序。
现在,我们根据运行应用程序的设备配置控件的可见性和属性。通过使用sap.ui.Device API并定义一个设备模型,我们将使应用程序在许多设备上看起来很棒。
webapp/view/HelloPanel.view.xml
<mvc:View
controllerName="sap.ui.demo.walkthrough.controller.HelloPanel"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc">
<Panel
headerText="{i18n>helloPanelTitle}"
class="sapUiResponsiveMargin"
width="auto"
expandable="{device>/system/phone}"
expanded="{= !${device>/system/phone} }">
<content>
<Button
id="helloDialogButton"
icon="sap-icon://world"
text="{i18n>openDialogButtonText}"
press=".onOpenDialog"
class="sapUiSmallMarginEnd sapUiVisibleOnlyOnDesktop"/>
<Button
text="{i18n>showHelloButtonText}"
press=".onShowHello"
class="myCustomButton"/>
<Input
value="{/recipient/name}"
valueLiveUpdate="true"
width="60%"/>
<FormattedText
htmlText="Hello {/recipient/name}"
class="sapUiSmallMargin sapThemeHighlight-asColor myCustomText"/>
</content>
</Panel>
</mvc:View>
我们添加了两个可扩展的新属性并将其扩展到HelloPanel。在屏幕较小的设备上,用户现在可以关闭或打开面板,为下面的表留出更多的空间。可扩展属性绑定到名为device的模型和路径/系统/电话。因此,面板只能在电话设备上扩展。设备模型由SAPUI5的sap.ui.Device API填充。扩展属性控制面板的状态,我们使用表达式绑定语法在手机设备上关闭它,并在所有其他设备上扩展面板。SAPUI5的设备API提供了更多的功能来检测各种设备特定的设置,请查看文档以了解更多细节。
设备API基于用户代理和设备的许多其他属性来检测设备类型(手机、平板电脑、桌面)。因此,简单地缩小屏幕尺寸并不会改变设备类型。要测试此功能,您必须在浏览器中启用设备模拟,或在实际设备上打开设备模拟。
当我们设置像sapUiVisibleOnlyOnDesktop或sapUiHideOnDesktop这样的CSS类时,我们也可以根据设备类型隐藏单个控件。我们只在桌面设备上显示打开对话框的按钮,而在其他设备上隐藏它。有关更多选项,请参阅下面链接的文档。
webapp/Component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel",
"./controller/HelloDialog",
"sap/ui/Device"
], function (UIComponent, JSONModel, HelloDialog, Device) {
"use strict";
return UIComponent.extend("sap.ui.demo.walkthrough.Component", {
metadata: {
manifest: "json"
},
init: function () {
// call the init function of the parent
UIComponent.prototype.init.apply(this, arguments);
// set data model
var oData = {
recipient: {
name: "World"
}
};
var oModel = new JSONModel(oData);
this.setModel(oModel);
// disable batch grouping for v2 API of the northwind service
this.getModel("invoice").setUseBatch(false);
// set device model
var oDeviceModel = new JSONModel(Device);
oDeviceModel.setDefaultBindingMode("OneWay");
this.setModel(oDeviceModel, "device");
// set dialog
this._helloDialog = new HelloDialog(this.getRootControl());
// create the views based on the url/hash
this.getRouter().initialize();
},
exit : function () {
this._helloDialog.destroy();
delete this._helloDialog;
},
openHelloDialog : function () {
this._helloDialog.open();
}
});
});
在app组件中,我们给sap.ui.Device添加了一个依赖,并在init方法中初始化设备模型。我们可以简单地传递已加载的依赖项设备到JSONModel的构造函数。这将使SAPUI5设备API的大部分属性作为JSON模型可用。然后在组件上将模型设置为命名模型,这样我们就可以在数据绑定中引用它,就像我们在上面的视图中看到的那样。
我们必须将绑定模式设置为单向模式,因为设备模型是只读的,并且我们希望在将控件的属性绑定到它时避免意外更改模型。默认情况下,SAPUI5中的模型是双向的(TwoWay)。当属性更改时,绑定的模型值也会更新。
你可以使用浏览器的开发工具测试应用的设备特定功能。例如在谷歌Chrome中,你可以模拟平板电脑或手机,很容易看到效果。SAPUI5的一些响应选项仅在加载应用程序时设置,所以你可能需要重新加载页面才能看到结果。
webapp/view/Detail.view.xml
<mvc:View
controllerName="sap.ui.demo.walkthrough.controller.Detail"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
xmlns:wt="sap.ui.demo.walkthrough.control">
<Page
title="{i18n>detailPageTitle}"
showNavButton="true"
navButtonPress=".onNavBack">
<ObjectHeader
responsive="true"
fullScreenOptimized="true" "----------------------------------------------------------------------"
number="{
parts: [{path: 'invoice>ExtendedPrice'}, {path: 'view>/currency'}],
type: 'sap.ui.model.type.Currency',
formatOptions: {
showMeasure: false
}
}"
numberUnit="{view>/currency}"
intro="{invoice>ShipperName}"
title="{invoice>ProductName}">
<attributes>
<ObjectAttribute title="{i18n>quantityTitle}" text="{invoice>Quantity}"></ObjectAttribute>
<ObjectAttribute title="{i18n>dateTitle}" text="{
path: 'invoice>ShippedDate',
type: 'sap.ui.model.type.Date',
formatOptions: {
style: 'long',
source: {
pattern: 'yyyy-MM-ddTHH:mm:ss'
}
}
}"/>
</attributes>
</ObjectHeader>
<wt:ProductRating id="rating" class="sapUiSmallMarginBeginEnd" change=".onRatingChange"/>
</Page>
</mvc:View>
一些控件已经具有可配置的内置响应功能。通过将响应属性设置为true和fullScreenOptimized属性设置为true, ObjectHeader控件可以被置于一个更灵活的模式中。这将根据设备大小在屏幕的不同位置显示我们添加到视图的数据。
我们还将前面步骤列表中的number和numberUnit字段添加到ObjectHeader,并使用与前面步骤中货币类型相同的格式化器。然后我们定义两个属性:发票的数量和作为数据模型一部分的发货日期。到目前为止,我们还没有从发票JSON文件中使用这个shippedDate字段,它包含一个典型字符串格式的日期。
现在,我们使用Date类型,并在格式选项的源代码部分提供日期格式的模式。它将显示更易于阅读的格式化日期文本,也适合小屏幕设备。
webapp/controller/Detail.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/routing/History",
"sap/m/MessageToast",
"sap/ui/model/json/JSONModel",
"sap/ui/core/UIComponent"
], function (Controller, History, MessageToast, JSONModel, UIComponent) {
"use strict";
return Controller.extend("sap.ui.demo.walkthrough.controller.Detail", {
onInit : function () {
var oViewModel = new JSONModel({
currency: "EUR"
});
this.getView().setModel(oViewModel, "view");
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.getRoute("detail").attachPatternMatched(this._onObjectMatched, this);
},
_onObjectMatched : …
});
在Detail控制器中,我们只需添加带有货币定义的视图模型,以正确显示数字。代码与InvoiceList控制器文件。
webapp/i18n/i18n.properties
# Detail Page
detailPageTitle=Walkthrough - Details
ratingConfirmation=You have rated this product with {0} stars
dateTitle=Order date
quantityTitle=Quantity
我们将列名和属性标题添加到i18n文件中。当我们缩小浏览器的屏幕尺寸或在一个小设备上打开应用程序时,我们可以看到结果。
约定
为手机、平板电脑和桌面设备的不同屏幕尺寸优化应用程序。