Step 10: Implement “Lazy Loading”
通过避免加载不可见的资源来提高浏览器的反映速度,我们称这种方式为延迟加载(lazy loading)。
修改Resume.view.xml
<mvc:View controllerName="sap.ui.demo.nav.controller.employee.Resume" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Page title="{i18n>ResumeOf} {FirstName} {LastName}" id="employeeResumePage" showNavButton="true" navButtonPress=".onNavBack"> <content> <IconTabBar id="iconTabBar" headerBackgroundDesign="Transparent" class="sapUiResponsiveContentPadding" binding="{Resume}" select=".onTabSelect" selectedKey="{view>/selectedTabKey}"> <items> <IconTabFilter id="infoTab" text="{i18n>tabInfo}" key="Info"> <Text text="{Information}"/> </IconTabFilter> <IconTabFilter id="projectsTab" text="{i18n>Projects}" key="Projects"> <mvc:XMLView viewName="sap.ui.demo.nav.view.employee.ResumeProjects"></mvc:XMLView> </IconTabFilter> <IconTabFilter id="hobbiesTab" text="{i18n>Hobbies}" key="Hobbies"> <!-- place content via lazy loading --> </IconTabFilter> <IconTabFilter id="notesTab" text="{i18n>Notes}" key="Notes"> <!-- place content via lazy loading --> </IconTabFilter> </items> </IconTabBar> </content> </Page> </mvc:View>
为了说明临时加载,我们实现了只有当用户在IconTabBar: Hobbies和Notes中为两个tag选择相应的tab时才加载内容。为每个IconTabFilter都是设置了一个id,以便在之后的路由配置他们。
在resume view中,我们删除了Hobbies和Notes tab的内容,之后我们将用导航特性动态填充它们。
创建ResumeHobbies.view.xml
<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Text text="{Hobbies}"/> </mvc:View>
创建ResumeNotes.view.xml
<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Text text="{Notes}"/> </mvc:View>
修改Resume.controller.js
sap.ui.define([ "sap/ui/demo/nav/controller/BaseController", "sap/ui/model/json/JSONModel" ], function (BaseController, JSONModel) { "use strict"; var _aValidTabKeys = ["Info", "Projects", "Hobbies", "Notes"]; return BaseController.extend("sap.ui.demo.nav.controller.employee.Resume", { ... _onRouteMatched : function (oEvent) { var oArgs, oView, oQuery; oArgs = oEvent.getParameter("arguments"); oView = this.getView(); oView.bindElement({ ... }); oQuery = oArgs["?query"]; if (oQuery && _aValidTabKeys.indexOf(oQuery.tab) > -1){ oView.getModel("view").setProperty("/selectedTabKey", oQuery.tab); // support lazy loading for the hobbies and notes tab if (oQuery.tab === "Hobbies" || oQuery.tab === "Notes"){ // the target is either "resumeTabHobbies" or "resumeTabNotes" this.getRouter().getTargets().display("resumeTab" + oQuery.tab); } } else { // the default query param should be visible at all time this.getRouter().navTo("employeeResume", { employeeId : oArgs.employeeId, query: { tab : _aValidTabKeys[0] } },true /*no history*/); } }, ... }); });
当所选择的tab是Hobbies或Notes的时候,我们通过路由去寻找相应的target,并将他显示在页面。当选择的tab不是Hobbies或Notes时,不会触发路由,所以不用读取页面不会被显示的资源。
这里有效的target是resumeTabHobbies和resumeTabNotes,我们需要在路由中追加这两个target。
修改manifest.json
{ "_version": "1.12.0", "sap.app": { ... }, "sap.ui": { ... }, "sap.ui5": { ... "routing": { "config": { "routerClass": "sap.m.routing.Router", "viewType": "XML", "viewPath": "sap.ui.demo.nav.view", "controlId": "app", "controlAggregation": "pages", "transition": "slide", "bypassed": { "target": "notFound" } }, "routes": [{ ... }, { "pattern": "employees/{employeeId}/resume:?query:", "name": "employeeResume", "target": "employeeResume" }], "targets": { ... "employeeResume": { "viewId": "resume", "viewName": "employee.Resume", "viewLevel" : 4, "transition": "flip" }, "resumeTabHobbies": { "viewId": "resumeHobbies", "parent": "employeeResume", "viewPath": "sap.ui.demo.nav.view.employee", "viewName": "ResumeHobbies", "controlId": "hobbiesTab", "controlAggregation": "content" }, "resumeTabNotes": { "viewId": "resumeNotes", "parent": "employeeResume", "viewPath": "sap.ui.demo.nav.view.employee", "viewName": "ResumeNotes", "controlId": "notesTab", "controlAggregation": "content" } } } } }
添加了两个target,resumeTabHobbies和resumeTabNotes,其中的配置信息会覆盖默认的config中的配置信息。
target resumeTabHobbies的parent属性为employeeResume。parent的属性值,是另外一个target值,在这个例子中,确保在resumeTabHobbies显示之前,employeeResume会被加载。这可以看作是一个视图之间的依赖。
通过设置controlId和controlAggregation属性,路由器将视图ResumeHobbies放入ID hobbiesTab的IconTabFilter控件的Aggregation中。
每个target,只能定义一个parent。controlId属性设置为parent view的contriol,这里的parent view 特指target中设置的view。
这样我们就实现了延迟加载,只在第一次被点击的时候进行加载。
Step 11: Assign Multiple Targets
使用一个路由的多个目标,按下按钮会,打开一个包含两个部分的新页面。
修改Home.view.xml
<mvc:View controllerName="sap.ui.demo.nav.controller.Home" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Page title="{i18n>homePageTitle}" class="sapUiResponsiveContentPadding"> <content> <Button id="displayNotFoundBtn" text="{i18n>DisplayNotFound}" press=".onDisplayNotFound" class="sapUiTinyMarginEnd"/> <Button id="employeeListBtn" text="{i18n>ShowEmployeeList}" press=".onNavToEmployees" class="sapUiTinyMarginEnd"/> <Button id="employeeOverviewBtn" text="{i18n>ShowEmployeeOverview}" press=".onNavToEmployeeOverview" class="sapUiTinyMarginEnd"/> </content> </Page> </mvc:View>
添加一个新的按钮,当按钮被点击时,触发onNavToEmployeeOverview。
修改Home.controller.js
sap.ui.define([ "sap/ui/demo/nav/controller/BaseController" ], function (BaseController) { "use strict"; return BaseController.extend("sap.ui.demo.nav.controller.Home", { ... onNavToEmployees : function () { this.getRouter().navTo("employeeList"); }, onNavToEmployeeOverview : function () { this.getRouter().navTo("employeeOverview"); } }); });
修改manifest.json
{ "_version": "1.12.0", "sap.app": { ... }, "sap.ui": { ... }, "sap.ui5": { ... "routing": { "config": { "routerClass": "sap.m.routing.Router", "viewType": "XML", "viewPath": "sap.ui.demo.nav.view", "controlId": "app", "controlAggregation": "pages", "transition": "slide", "bypassed": { "target": "notFound" } }, "routes": [{ "pattern": "", "name": "appHome", "target": "home" }, { "pattern": "employees", "name": "employeeList", "target": "employees" }, { "pattern": "employees/overview", "name": "employeeOverview", "target": ["employeeOverviewTop", "employeeOverviewContent"] }, { "pattern": "employees/{employeeId}", "name": "employee", "target": "employee" }, { "pattern": "employees/{employeeId}/resume:?query:", "name": "employeeResume", "target": "employeeResume" }], "targets": { ... "resumeTabNotes": { "viewId": "resumeNotes", "parent": "employeeResume", "viewPath": "sap.ui.demo.nav.view.employee", "viewName": "ResumeNotes", "controlId": "notesTab", "controlAggregation": "content" }, "employeeOverview": { "viewId": "employeeOverview", "viewPath": "sap.ui.demo.nav.view.employee.overview", "viewName": "EmployeeOverview", "viewLevel" : 2 }, "employeeOverviewTop": { "viewId": "employeeOverviewTop", "parent": "employeeOverview", "viewPath": "sap.ui.demo.nav.view.employee.overview", "viewName": "EmployeeOverviewTop", "controlId": "EmployeeOverviewParent", "controlAggregation": "content" }, "employeeOverviewContent": { "viewId": "employeeOverviewContent", "parent": "employeeOverview", "viewPath": "sap.ui.demo.nav.view.employee.overview", "viewName": "EmployeeOverviewContent", "controlId": "EmployeeOverviewParent", "controlAggregation": "content" } } } } }
添加了新的路由employeeOverview,使用数组同时引用两个target:employeeOverviewTop和employeeOverviewContent。
target employeeOverviewTop和employeeOverviewContent都将target employeeOverview作为parent 引用,因为我们希望将它们都放在parent中。我们还设置了viewPath。
路由器确保在匹配了相应的路由并显示了目标时,除了目标视图外,还加载了父视图。
新建EmployeeOverview.view.xml
<mvc:View
controllerName="sap.ui.demo.nav.controller.employee.overview.EmployeeOverview"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc">
<Page id="EmployeeOverviewParent" title="{i18n>EmployeeOverview}"
showNavButton="true"
navButtonPress=".onNavBack"
class="sapUiResponsiveContentPadding">
<content>
<!-- inserted by routing -->
</content>
</Page>
</mvc:View>
新建EmployeeOverview.controller.js
sap.ui.define([
"sap/ui/demo/nav/controller/BaseController"
], function (BaseController) {
"use strict";
return BaseController.extend("sap.ui.demo.nav.controller.employee.overview.EmployeeOverview", {
});
});
新建EmployeeOverviewTop.view.xml
<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" class="sapUiMediumMarginBottom"> <Title text="{i18n>EmployeeOverviewTop}"/> </mvc:View>
新建EmployeeOverviewContent.view.xml
<mvc:View controllerName="sap.ui.demo.nav.controller.employee.overview.EmployeeOverviewContent" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Table id="employeesTable" items="{/Employees}"> <headerToolbar> <Toolbar> <Title text="{i18n>Employees}" level="H2"/> <ToolbarSpacer /> <SearchField id="searchField" search=".onSearchEmployeesTable" width="50%"/> <Button icon="sap-icon://sort" press=".onSortButtonPressed"/> </Toolbar> </headerToolbar> <columns> <Column id="employeeIDCol"><Text text="{i18n>EmployeeID}"/></Column> <Column id="firstNameCol" demandPopin="true"><Text text="{i18n>FirstName}"/></Column> <Column id="lastNameCol" demandPopin="true"><Text text="{i18n>LastName}"/></Column> <Column id="addressCol" minScreenWidth="Tablet" demandPopin="true"><Text text="{i18n>Address}"/></Column> <Column id="cityCol" minScreenWidth="Tablet" demandPopin="true"><Text text="{i18n>City}"/></Column> <Column id="regionCol" minScreenWidth="Tablet" demandPopin="true"><Text text="{i18n>Region}"/></Column> <Column id="postalCodeCol" minScreenWidth="Tablet" demandPopin="true"><Text text="{i18n>PostalCode}"/></Column> <Column id="countryCol" minScreenWidth="Tablet" demandPopin="true"><Text text="{i18n>Country}"/></Column> <Column id="homePhoneCol" minScreenWidth="Tablet" demandPopin="true" hAlign="Right"><Text text="{i18n>Phone}"/></Column> </columns> <items> <ColumnListItem> <cells> <Text text="{EmployeeID}"/> <Text text="{FirstName}"/> <Text text="{LastName}"/> <Text text="{Address}"/> <Text text="{City}"/> <Text text="{Region}"/> <Text text="{PostalCode}"/> <Text text="{Country}"/> <Text text="{HomePhone}"/> </cells> </ColumnListItem> </items> </Table> </mvc:View>
SearchField允许在表中搜索,Button可以打开一个对话框调整顺序。
新建EmployeeOverviewContent.controller.js
sap.ui.define([ "sap/ui/demo/nav/controller/BaseController", "sap/ui/model/Filter", "sap/ui/model/FilterOperator", "sap/ui/model/Sorter", "sap/m/ViewSettingsDialog", "sap/m/ViewSettingsItem" ], function( BaseController, Filter, FilterOperator, Sorter, ViewSettingsDialog, ViewSettingsItem ) { "use strict"; return BaseController.extend("sap.ui.demo.nav.controller.employee.overview.EmployeeOverviewContent", { onInit: function () { this._oTable = this.byId("employeesTable"); this._oVSD = null; this._sSortField = null; this._bSortDescending = false; this._aValidSortFields = ["EmployeeID", "FirstName", "LastName"]; this._sSearchQuery = null; this._initViewSettingsDialog(); }, onSortButtonPressed : function () { this._oVSD.open(); }, onSearchEmployeesTable : function (oEvent) { this._applySearchFilter( oEvent.getSource().getValue() ); }, _initViewSettingsDialog : function () { this._oVSD = new ViewSettingsDialog("vsd", { confirm: function (oEvent) { var oSortItem = oEvent.getParameter("sortItem"); this._applySorter(oSortItem.getKey(), oEvent.getParameter("sortDescending")); }.bind(this) }); // init sorting (with simple sorters as custom data for all fields) this._oVSD.addSortItem(new ViewSettingsItem({ key: "EmployeeID", text: "Employee ID", selected: true // by default the MockData is sorted by EmployeeID })); this._oVSD.addSortItem(new ViewSettingsItem({ key: "FirstName", text: "First Name", selected: false })); this._oVSD.addSortItem(new ViewSettingsItem({ key: "LastName", text: "Last Name", selected: false })); }, _applySearchFilter : function (sSearchQuery) { var aFilters, oFilter, oBinding; // first check if we already have this search value if (this._sSearchQuery === sSearchQuery) { return; } this._sSearchQuery = sSearchQuery; this.byId("searchField").setValue(sSearchQuery); // add filters for search aFilters = []; if (sSearchQuery && sSearchQuery.length > 0) { aFilters.push(new Filter("FirstName", FilterOperator.Contains, sSearchQuery)); aFilters.push(new Filter("LastName", FilterOperator.Contains, sSearchQuery)); oFilter = new Filter({ filters: aFilters, and: false }); // OR filter } else { oFilter = null; } // update list binding oBinding = this._oTable.getBinding("items"); oBinding.filter(oFilter, "Application"); }, /** * Applies sorting on our table control. * @param {string} sSortField the name of the field used for sorting * @param {string} sortDescending true or false as a string or boolean value to specify a descending sorting * @private */ _applySorter : function (sSortField, sortDescending){ var bSortDescending, oBinding, oSorter; // only continue if we have a valid sort field if (sSortField && this._aValidSortFields.indexOf(sSortField) > -1) { // convert the sort order to a boolean value if (typeof sortDescending === "string") { bSortDescending = sortDescending === "true"; } else if (typeof sortDescending === "boolean") { bSortDescending = sortDescending; } else { bSortDescending = false; } // sort only if the sorter has changed if (this._sSortField && this._sSortField === sSortField && this._bSortDescending === bSortDescending) { return; } this._sSortField = sSortField; this._bSortDescending = bSortDescending; oSorter = new Sorter(sSortField, bSortDescending); // sync with View Settings Dialog this._syncViewSettingsDialogSorter(sSortField, bSortDescending); oBinding = this._oTable.getBinding("items"); oBinding.sort(oSorter); } }, _syncViewSettingsDialogSorter : function (sSortField, bSortDescending) { // the possible keys are: "EmployeeID" | "FirstName" | "LastName" // Note: no input validation is implemented here this._oVSD.setSelectedSortItem(sSortField); this._oVSD.setSortDescending(bSortDescending); } }); });
修改i18n.properties
EmployeeOverview=Employee Overview
ShowEmployeeOverview=Show Employee Overview
EmployeeOverviewTop=Employee Overview Top
Region=Region
EmployeeID=Employee ID
Phone=Phone
Employees=Employees
Step 12: Make a Search Bookmarkable
在url中加入书签标记
修改manifest.json
{ "_version": "1.12.0", "sap.app": { ... }, "sap.ui": { ... }, "sap.ui5": { ... "routing": { "config": { "routerClass": "sap.m.routing.Router", "viewType": "XML", "viewPath": "sap.ui.demo.nav.view", "controlId": "app", "controlAggregation": "pages", "transition": "slide", "bypassed": { "target": "notFound" } }, "routes": [{ "pattern": "", "name": "appHome", "target": "home" }, { "pattern": "employees", "name": "employeeList", "target": "employees" }, { "pattern": "employees/overview:?query:", "name": "employeeOverview", "target": ["employeeOverviewTop", "employeeOverviewContent"] }, { "pattern": "employees/{employeeId}", "name": "employee", "target": "employee" }, { "pattern": "employees/{employeeId}/resume:?query:", "name": "employeeResume", "target": "employeeResume" }], "targets": { ... } } } }
为了使搜索的内容可以标记,应该考虑相应的路由pattern如果记载搜索的内容。所以使用/#/employees/overview?search=mySearchQueryString这种格式来标记搜索的内容。追加一个:?query:参数到路由employeeOverview。
要用search作为搜索内容的标记。
修改EmployeeOverviewContent.controller.js
sap.ui.define([ "sap/ui/demo/nav/controller/BaseController", "sap/ui/model/Filter", "sap/ui/model/FilterOperator", "sap/ui/model/Sorter", "sap/m/ViewSettingsDialog", "sap/m/ViewSettingsItem" ], function( BaseController, Filter, FilterOperator, Sorter, ViewSettingsDialog, ViewSettingsItem ) { "use strict"; return BaseController.extend("sap.ui.demo.nav.controller.employee.overview.EmployeeOverviewContent", { onInit: function () { var oRouter = this.getRouter(); this._oTable = this.byId("employeesTable"); this._oVSD = null; this._sSortField = null; this._bSortDescending = false; this._aValidSortFields = ["EmployeeID", "FirstName", "LastName"]; this._sSearchQuery = null; this._oRouterArgs = null; this._initViewSettingsDialog(); // make the search bookmarkable oRouter.getRoute("employeeOverview").attachMatched(this._onRouteMatched, this); }, _onRouteMatched : function (oEvent) { // save the current query state this._oRouterArgs = oEvent.getParameter("arguments"); this._oRouterArgs.query = this._oRouterArgs["?query"] || {}; if (this._oRouterArgs.query) { // search/filter via URL hash this._applySearchFilter(this._oRouterArgs.query.search); } }, onSortButtonPressed : function (oEvent) { this._oVSD.open(); }, onSearchEmployeesTable : function (oEvent) { var oRouter = this.getRouter(); // update the hash with the current search term this._oRouterArgs.query.search = oEvent.getSource().getValue(); oRouter.navTo("employeeOverview",this._oRouterArgs, true /*no history*/); }, ... }); });
在controller中处理路由中的查询参数。
在onInit函数中,监听路由,如果路由为employeeOverview,则触发事件_onRouteMatched。通过接收到的event,获取到路由的参数。在获取到的参数中,会包含一个?query属性,该属性会定义指向的搜索内容。
如果有该属性,那么将其保存到 this._oRouterArgs.query中,否则设置为空。如果query上有search的内容,那么将调用this._applySearchFilter(this._oRouterArgs.query.search)来进行查询。
在onSearchEmployeesTable函数中取得在检索框中输入的内容,并且放入路由的参数中,用于在之后的页面中进行传递。
Step 13: Make Table Sorting Bookmarkable
在url中标记表的排序状态
修改EmployeeOverviewContent.controller.js
sap.ui.define([ "sap/ui/demo/nav/controller/BaseController", "sap/ui/model/Filter", "sap/ui/model/FilterOperator", "sap/ui/model/Sorter", "sap/m/ViewSettingsDialog", "sap/m/ViewSettingsItem" ], function( BaseController, Filter, FilterOperator, Sorter, ViewSettingsDialog, ViewSettingsItem ) { "use strict"; return BaseController.extend("sap.ui.demo.nav.controller.employee.overview.EmployeeOverviewContent", { onInit: function () { ... }, _onRouteMatched : function (oEvent) { // save the current query state this._oRouterArgs = oEvent.getParameter("arguments"); this._oRouterArgs.query = this._oRouterArgs["?query"] || {}; delete this._oRouterArgs["?query"]; if (this._oRouterArgs.query) { // search/filter via URL hash this._applySearchFilter(this._oRouterArgs.query.search); // sorting via URL hash this._applySorter(this._oRouterArgs.query.sortField, this._oRouterArgs.query.sortDescending); } }, ... _initViewSettingsDialog : function () { var oRouter = this.getRouter(); this._oVSD = new sap.m.ViewSettingsDialog("vsd", { confirm: function (oEvent) { var oSortItem = oEvent.getParameter("sortItem");
var oRouter = this.getRouter(); this._oRouterArgs.query.sortField = oSortItem.getKey(); this._oRouterArgs.query.sortDescending = oEvent.getParameter("sortDescending"); oRouter.navTo("employeeOverview",this._oRouterArgs, true /*without history*/); }.bind(this) }); ... }, ... }); });
与step12类似,在query中追加了两个参数,sortField与sortDescending。在_onRouteMatched函数中,从url中获取这两个参数。用来进行下一步的处理。
在_initViewSettingsDialog函数中,当confirm方法触发时,获取参数,并将参数放入路由中。
Step 14: Make Dialogs Bookmarkable
记录对话框是否表示的状态,与step12,13类似。
sap.ui.define([ "sap/ui/demo/nav/controller/BaseController", "sap/ui/model/Filter", "sap/ui/model/FilterOperator", "sap/ui/model/Sorter", "sap/m/ViewSettingsDialog", "sap/m/ViewSettingsItem" ], function( BaseController, Filter, FilterOperator, Sorter, ViewSettingsDialog, ViewSettingsItem ) { "use strict"; return BaseController.extend("sap.ui.demo.nav.controller.employee.overview.EmployeeOverviewContent", { onInit: function () { ... }, _onRouteMatched : function (oEvent) { // save the current query state this._oRouterArgs = oEvent.getParameter("arguments"); this._oRouterArgs.query = this._oRouterArgs["?query"] || {}; delete this._oRouterArgs["?query"]; if (this._oRouterArgs.query) { // search/filter via URL hash this._applySearchFilter(this._oRouterArgs.query.search); // sorting via URL hash this._applySorter(this._oRouterArgs.query.sortField, this._oRouterArgs.query.sortDescending); // show dialog via URL hash if (!!this._oRouterArgs.query.showDialog) { this._oVSD.open(); } } }, onSortButtonPressed : function (oEvent) { var oRouter = this.getRouter(); this._oRouterArgs.query.showDialog = 1; oRouter.navTo("employeeOverview",this._oRouterArgs); }, ... _initViewSettingsDialog : function () { var oRouter = this.getRouter(); this._oVSD = new sap.m.ViewSettingsDialog("vsd", { confirm: function (oEvent) { var oSortItem = oEvent.getParameter("sortItem"); this._oRouterArgs.query.sortField = oSortItem.getKey(); this._oRouterArgs.query.sortDescending = oEvent.getParameter("sortDescending"); delete this._oRouterArgs.query.showDialog; oRouter.navTo("employeeOverview",this._oRouterArgs, true /*without history*/); }.bind(this), cancel : function (oEvent){ delete this._oRouterArgs.query.showDialog; oRouter.navTo("employeeOverview",this._oRouterArgs, true /*without history*/); }.bind(this) }); ... }, ... }); });
Step 15: Reuse an Existing Route
使用已经存在的导航。
修改EmployeeOverviewContent.view.xml
<mvc:View controllerName="sap.ui.demo.nav.controller.employee.overview.EmployeeOverviewContent" xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc"> <Table id="employeesTable" items="{/Employees}" itemPress=".onItemPressed"> <headerToolbar> ... </headerToolbar> <columns> ... </columns> <items> <ColumnListItem type="Active"> <cells> ... </cells> </ColumnListItem> </items> </Table> </mvc:View>
为itemPress注册一个onItemPressed事件,并且将Item的type设置为Active,这样就可以对item进行点击。
修改EmployeeOverviewContent.controller.js
sap.ui.define([ "sap/ui/demo/nav/controller/BaseController", "sap/ui/model/Filter", "sap/ui/model/FilterOperator", "sap/ui/model/Sorter", "sap/m/ViewSettingsDialog", "sap/m/ViewSettingsItem" ], function( BaseController, Filter, FilterOperator, Sorter, ViewSettingsDialog, ViewSettingsItem ) { "use strict"; return BaseController.extend("sap.ui.demo.nav.controller.employee.overview.EmployeeOverviewContent", { ... _syncViewSettingsDialogSorter : function (sSortField, bSortDescending) { // the possible keys are: "EmployeeID" | "FirstName" | "LastName" // Note: no input validation is implemented here this._oVSD.setSelectedSortItem(sSortField); this._oVSD.setSortDescending(bSortDescending); }, onItemPressed : function (oEvent) { var oItem, oCtx, oRouter; oItem = oEvent.getParameter("listItem"); oCtx = oItem.getBindingContext(); this.getRouter().navTo("employeeResume",{ employeeId : oCtx.getProperty("EmployeeID"), query : { tab : "Info" } }); } }); });
在controller中添加onItemPressed函数,当item被点击时,可以触发该事件。
这样就可以导航到路由employeeResume中。
Step 16: Handle Invalid Hashes by Listening to Bypassed Events
使用Bypassed事件,来监听无效的hash值。
修改App.controller.js
sap.ui.define([ "sap/ui/demo/nav/controller/BaseController" ], function (BaseController) { "use strict"; return BaseController.extend("sap.ui.demo.nav.controller.App", { onInit: function () { // This is ONLY for being used within the tutorial. // The default log level of the current running environment may be higher than INFO, // in order to see the debug info in the console, the log level needs to be explicitly // set to INFO here. // But for application development, the log level doesn't need to be set again in the code. Log.setLevel(Log.Level.INFO); var oRouter = this.getRouter(); oRouter.attachBypassed(function (oEvent) { var sHash = oEvent.getParameter("hash"); // do something here, i.e. send logging data to the backend for analysis // telling what resource the user tried to access... Log.info("Sorry, but the hash '" + sHash + "' is invalid.", "The resource was not found."); }); } }); });
当路由中的hash值无效时,可以触发该事件。可以用来分析为何发生这种问题。
Step 17: Listen to Matched Events of Any Route
使用attachRouteMatched函数来监听所有的路由时间,用于进行分析路由被触发的频率等信息。
修改App.controller.js
sap.ui.define([ "sap/ui/demo/nav/controller/BaseController" ], function (BaseController) { "use strict"; return BaseController.extend("sap.ui.demo.nav.controller.App", { onInit: function () { var oRouter = this.getRouter(); oRouter.attachBypassed(function (oEvent) { var sHash = oEvent.getParameter("hash"); // do something here, i.e. send logging data to the back end for analysis // telling what resource the user tried to access... jQuery.sap.log.info("Sorry, but the hash '" + sHash + "' is invalid.", "The resource was not found."); }); oRouter.attachRouteMatched(function (oEvent){ var sRouteName = oEvent.getParameter("name"); // do something, i.e. send usage statistics to back end // in order to improve our app and the user experience (Build-Measure-Learn cycle) jQuery.sap.log.info("User accessed route " + sRouteName + ", timestamp = " + new Date().getTime()); }); } }); });
link https://sapui5.hana.ondemand.com/#/topic/1b6dcd39a6a74f528b27ddb22f15af0d