Show TOC

Step 8: Navigate with Flip TransitionLocate this document in the navigation structure

In this step, we want to illustrate how to navigate to a page with a custom transition animation. Both forward and backward navigation will use the “flip” transition but with a different direction. We will create a simple link on the Employee view that triggers a flip navigation to a page that displays the resume data of a certain employee. Pressing the Back button will navigate back to the Employee view with a reversed flip transition.

Preview
Figure 1: Employee Details page with Flip to Resume link
Figure 2: Resume page with multiple tabs
Figure 3: Not Found page for resume
Coding

You can view and download all files in the Explored app in the Demo Kit under Routing and Navigation - Step 8.

Figure 4: Folder structure for this step
webapp/view/employee/Employee.view.xml
<mvc:View
	controllerName="sap.ui.demo.nav.controller.employee.Employee"
	xmlns="sap.m"
	xmlns:mvc="sap.ui.core.mvc"
	xmlns:f="sap.ui.layout.form"
	busyIndicatorDelay="0">
	<Page
		id="employeePage"
		title="{i18n>EmployeeDetailsOf} {FirstName} {LastName}"
		showNavButton="true"
		navButtonPress="onNavBack"
		class="sapUiResponsiveContentPadding">
		<content>
			<Panel
				id="employeePanel"
				width="auto"
				class="sapUiResponsiveMargin sapUiNoContentPadding">
				<headerToolbar>
					<Toolbar>
						<Title text="{i18n>EmployeeIDColon} {EmployeeID}" level="H2"/>
						<ToolbarSpacer />
						<Link text="{i18n>FlipToResume}" tooltip="{i18n>FlipToResume.tooltip}" press="onShowResume" />
					</Toolbar>
				</headerToolbar>
				<content>
					...
				</content>
			</Panel>
		</content>
	</Page>
</mvc:View>

First we add the Flip to Resume link to the Employee Details view to trigger the navigation to the resume of the employee that is currently displayed.

webapp/controller/employee/Employee.controller.js
sap.ui.define([
	"sap/ui/demo/nav/controller/BaseController"
], function (BaseController) {
	"use strict";
	return BaseController.extend("sap.ui.demo.nav.controller.employee.Employee", {
		...
		_onBindingChange : function (oEvent) {
			// No data for the binding
			if (!this.getView().getBindingContext()) {
				this.getRouter().getTargets().display("notFound");
			}
		}
			...
		},
		onShowResume : function (oEvent) {
			var oCtx = this.getView().getElementBinding().getBoundContext();

			this.getRouter().navTo("employeeResume", {
				employeeId : oCtx.getProperty("EmployeeID")
			});
		}

	});
});

Then we change the Employee.controller.js file by adding the press handler onShowResume for the Flip to Resume link. The handler simply navigates to a new route employeeResume and fills the mandatory parameter employeeId with the property EmployeeID from the view’s bound context. The route employeeResume is not available yet, so we will have to add it to our routing configuration.

webapp/manifest.json
{
	"_version": "1.1.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/{employeeId}",
				"name": "employee",
				"target": "employee"
			}, {
				"pattern": "employees/{employeeId}/resume",
				"name": "employeeResume",
				"target": "employeeResume"
			}],
			"targets": {
				"home": {
					"viewName": "Home",
					"viewLevel" : 1
				},
				"notFound": {
					"viewName": "NotFound",
					"transition": "show"
				},
				"employees": {
					"viewPath": "sap.ui.demo.nav.view.employee",
					"viewName": "EmployeeList",
					"viewLevel" : 2
				},
				"employee": {
					"viewName": "employee.Employee",
					"viewLevel" : 3
				},
				"employeeResume": {
					"viewName": "employee.Resume",
					"viewLevel" : 4,
					"transition": "flip"
				}
			}
		}
	}
}

In the routing configuration, we add a new route employeeResume which references a target with the same name. The route’s pattern expects an {employeeId} as a mandatory parameter and ends with the static string /resume.

The target employeeResume references the view employee.Resume that we are about to create. The target’s viewLevel is 4; compared to the employee target this is one level lower again. To configure a flip navigation, we simply set the transition of our target to flip. Together with the correct viewLevel configuration this will trigger the correct forward and backward flip navigation whenever the target is displayed.
Note
Possible values for the transition parameter are:
  • slide (default)

  • flip

  • show

  • fade

You can also implement your own transitions and add it to a control that extends sap.m.NavContainer (for example, sap.m.App or sap.m.SplitApp). For more information, see the API Reference for NavContainer.

webapp/view/employee/Resume.view.xml (New)
<mvc:View
	controllerName="sap.ui.demo.nav.controller.employee.Resume"
	xmlns="sap.m"
	xmlns:mvc="sap.ui.core.mvc"
	xmlns:f="sap.ui.layout.form"
	busyIndicatorDelay="0">
	<Page
		title="{i18n>ResumeOf} {FirstName} {LastName}"
		id="employeeResumePage"
		showNavButton="true"
		navButtonPress="onNavBack"
		class="sapUiResponsiveContentPadding">
		<content>
			<IconTabBar
				id="iconTabBar"
				class="sapUiResponsiveContentPadding"
				binding="{Resume}">
				<items>
					<IconTabFilter id="infoTab" text="{i18n>Info}" 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">
						<Text text="{Hobbies}" />
					</IconTabFilter>
					<IconTabFilter id="notesTab" text="{i18n>Notes}" key="Notes">
						<Text text="{Notes}" />
					</IconTabFilter>
				</items>
			</IconTabBar>
		</content>
	</Page>
</mvc:View>

Create a file Resume.view.xml inside the webapp/view/employee folder. The view uses an IconTabBar to display the resume data. Therefore, its binding attribute is set to {Resume}.

In the IconTabBar we display four tabs. Three of them simply use a Text control to display the data from the service. The Projects tab uses a nested XML view to display the projects of the employee. SAPUI5 takes care of loading the XML view automatically when the user navigates to the Resume page.

webapp/controller/employee/Resume.controller.js (New)
sap.ui.define([
	"sap/ui/demo/nav/controller/BaseController"
], function (BaseController) {
	"use strict";
	return BaseController.extend("sap.ui.demo.nav.controller.employee.Resume", {
		onInit: function () {
			var oRouter = this.getRouter();
			oRouter.getRoute("employeeResume").attachMatched(this._onRouteMatched, this);
		},
		_onRouteMatched : function (oEvent) {
			var oArgs, oView;
			oArgs = oEvent.getParameter("arguments");
			oView = this.getView();
			oView.bindElement({
				path : "/Employees(" + oArgs.employeeId + ")",
				events : {
					change: this._onBindingChange.bind(this),
					dataRequested: function (oEvent) {
						oView.setBusy(true);
					},
					dataReceived: function (oEvent) {
						oView.setBusy(false);
					}
				}
			});
		},
		_onBindingChange : function (oEvent) {
			// No data for the binding
			if (!this.getView().getBindingContext()) {
				this.getRouter().getTargets().display("notFound");
			}
		}
	});
});

Create a file Resumee.controller.js in the webapp/controller/employee folder. In this controller, we make sure to bind the view to the correct employee whenever the employeeResume route has matched. We have already used this approach in the previous step so you should be able to recognize the building blocks in the code above. Again, in case the user cannot be found we display the notFound target.

webapp/view/employee/ResumeProjects.view.xml (New)
<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc">
	<Text text="{Projects}" />
</mvc:View>
Create a file ResumeProjects.view.xml in the webapp/view/employee folder. This view does not have a controller as we don’t need it. It just displays a Text control with the projects text of the selected employee. It illustrates that using nested views works just fine in combination with navigation and routing in SAPUI5.
Note

For more complex applications, the performance is significantly increased if parts of the UI are only loaded when the user is actively selecting it. In this example, the view is always loaded even though the user never decided to display the project information. In the next steps, we will extend the UI so that the content is loaded “lazy” by SAPUI5 only when the filter item is clicked. The back-end service will fetch the data only on request and the UI will only have to be updated with the selected data instead of loading all data.

webapp/i18n/i18n.properties
...
ResumeOf=Resume of
Info=Info
Projects=Projects
Hobbies=Hobbies
Notes=Notes
FlipToResume=Flip to Resume
FlipToResume.tooltip=See the resume of this employee

Add the new texts to the i18n.properties file.

You can go to webapp/index.html#/employees/3 and click on the Flip to Resume link to be redirected with a nice flip transition to the employee’s resume. The back navigation uses a reverse flip navigation to get back to the Employee Details page. You can also directly navigate to webapp/index.html#/employees/3/resume or webapp/index.html#/employees/33/resume to see what happens.