Skip to Content
Technical Articles

A journey into the evolution of SplitApp Part 2: An Introduction to Flexible Column Layout + Dynamic Page Layout

Introduction & Recap

Good morning everyone, in the previous blog post I’ve introduced to you the basic knowledge of Flexible Column Layout and Dynamic Page Layout, a UI/UX pattern that will replace your old SlitApp layout that has been deprecated since SAPUI5 release 1.48.

In this blog post, I will explain how you can easily migrate from a SplitApp application to a Flexible Column Layout application in a matter of minutes.

The starting code base is from our previous SAPUI5 CRUD project application. From there, we will follow a step-by-step migration procedure, explaining some basic concept.

The state of the art of our application

Let’s take a look at the UI/UX of the current application so we can compare it at the end of the transformation

There’s nothing new here, it’s a basic Split App layout with CRUD operation so let’s move on.

Step 1 — Clone & Import the application from GitHub

So the first step is to clone the application from the latest tag release on GitHub. You can freely clone and import it into your WebIDE workspace.

Step 2 — Update the manifest.json, index.html, and App.view.xml

App.view.xml

The first thing we want to do is to replace out old SplitApp with the new FlexibleColumnLayout inside our App.xml.view (the main view loaded when the application is loaded).

Here’s the new code of our App.view.xml

<mvc:View
	xmlns:mvc="sap.ui.core.mvc"
	displayBlock="true"
	xmlns="sap.m"
	xmlns:f="sap.f">
	<App>
		<f:FlexibleColumnLayout 
			id="idAppControl"
			layout="{app>/layout}"
		/>
	</App>
</mvc:View>

You have to note a few important things:

  • I added a new XML namespace sap.f because our FlexibleColumnLayout is included in the SAP Fiori library of SAPUI5
  • We removed the SplitApp and we added our FCL inside an App
  • Out FLC has the layout property bound to app>/layout. We will use this binding later in our code to handle the FullScreen visualization of our second and third column

Index.html

As you can see in the code below we moved from the Shell to a ComponentContainer. This is the first step to remove Letterboxing from our layout.

<!DOCTYPE HTML>
<html>

	<head>
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta charset="UTF-8">

		<title>FlexibleColumnLayoutSample</title>

		<script id="sap-ui-bootstrap"
			src="../../resources/sap-ui-core.js"
			data-sap-ui-async="true"
			data-sap-ui-libs="sap.m"
			data-sap-ui-theme="sap_belize"
			data-sap-ui-compatVersion="edge"
			data-sap-ui-resourceroots='{"com.techedge.training.FlexibleColumnLayoutApp": "./"}'>
		</script>

		<link rel="stylesheet" type="text/css" href="css/style.css">

		<script>
			/*sap.ui.getCore().attachInit(function() {
				new sap.m.Shell({
					app: new sap.ui.core.ComponentContainer({
						height : "100%",
						name : "com.techedge.training.FlexibleColumnLayoutApp"
					})
				}).placeAt("content");
			});*/
			sap.ui.getCore().attachInit(function () {
				sap.ui.require([
					"sap/ui/core/ComponentContainer"
				], function (ComponentContainer) {
					new ComponentContainer({
						name : 'com.techedge.training.FlexibleColumnLayoutApp',
						height : "100%"
					}).placeAt('content');
				});
			});
		</script>
	</head>

	<body class="sapUiBody" id="content">
	</body>

</html>

Letterboxing

In web design, it’s common practice to restrict the user interface to a certain width in order to preserve its original aspect ratio. This way, the interface does not become distorted or stretched when adapting to larger screen sizes.

If the screen is wider than the set width restriction, blank areas to the left and right of the user interface will appear. In many cases, these areas are used to display advertisements. This design element is called letterboxing because it restricts the user interface to a certain width similar to the shape of a classical letterbox.

In our case, we need to remove the Letterboxing because we will need the max possible usable screen area to properly display three columns at one!

manifest.json

In our manifest, there are four important modification that we need to do

  • Add the configuration to enable the application to use the full-screen width (this is the second part to remove Letterboxing)
  • Add sap.f to the list of dependencies loaded with the application
  • Replace the router class from sap.m.routing.Router to sap.f.routing.Router in order to use the new Routing features
  • Update routes and targets to leverage the new property added by the new Router class and used by the Flexible Column Layout

Please note that this is only a part of the manifest.json content, I’ve only added the chunk we will change for the Routing

{
  "sap.ui5": {
    "routing": {
      "config": {
        "routerClass": "sap.f.routing.Router",
        "viewType": "XML",
        "async": true,
        "viewPath": "com.techedge.training.FlexibleColumnLayoutApp.view",
        "controlId": "idAppControl",
        "transition": "slide",
        "clearControlAggregation": false
      },
      "routes": [
        {
          "name": "TargetBusinessPartnerList",
          "pattern": "",
          "layout": "OneColumn",
          "target": [
            "TargeteBusinessPartnerList"
          ]
        },
        {
          "name": "TargetBusinessPartnerDetail",
          "pattern": "partner/:BusinessPartnerID:/",
          "layout": "TwoColumnsMidExpanded",
          "target": [
            "TargeteBusinessPartnerList",
            "TargetBusinessPartnerDetail"
          ]
        },
        {
          "name": "TargetBusinessPartnerSalesOrderDetail",
          "pattern": "partner/:BusinessPartnerID:/sale/:SalesOrderID:",
          "layout": "ThreeColumnsEndExpanded",
          "target": [
            "TargeteBusinessPartnerList",
            "TargetBusinessPartnerDetail",
            "TargetBusinessPartnerSalesOrderDetail"
          ]
        }
      ],
      "targets": {
        "TargeteBusinessPartnerList": {
          "controlAggregation": "beginColumnPages",
          "viewName": "BusinessPartnerList"
        },
        "TargetBusinessPartnerDetail": {
          "controlAggregation": "midColumnPages",
          "viewName": "BusinessPartnerDetail"
        },
        "TargetBusinessPartnerSalesOrderDetail": {
          "controlAggregation": "endColumnPages",
          "viewName": "BusinessPartnerSalesOrderDetail"
        }
      }
    }
  }
}

As you can see inside each Route element we have a new property called “layout”.

There are nine different layouts available at the moment, each one of them will change the default visualization of the Flexible Column Layout. In our case we’re going to use:

  • OneColumn when we’re in the home page and we just need to display the list of Business Partner
  • TwoColumnsMidExpanded that will display two columns with the middle one (on the right) expanded. We’re using this layout to display a typical Master-Detail view type when the user clicks on a Business Partner on the list.
  • ThreeColumnsEndExpanded that will display three columns with the latest one expanded. We’re using this layout to display also the pieces of information about the Business Partner Order List.

Each Route’s Target has a different property called “controlAggregation” that will specify in which FlexibleColumnLayout’s aggregation that target will be added.

In our scenario:

  • The BusinessPartnerList view will be added to the beginColumnPages aggregation (the first column)
  • The BusinessPartnerDetail view will be added to the midColumnPages aggregation (the second column)
  • The BusinessPartnerSalesOrderDetail view will be added to the endColumnPages aggregation (the third and last column)

Why is it so important to correctly configure the manifest.json? With a few lines of code, we have automatically configured the whole UI/UX behavior of our application. Isn’t it nice? 😉

Step 3 — Handle Full-Screen / Exit behavior

In this last part, we will explain how to allow the user to expand to full-screen one page of the FlexibleColumnLayout. This feature is really important because allows the user to take advantages of the full-screen width, something that is crucial when you have to deal with a lot of information inside a table with many columns.

<headerContent>
  <Button
    visible="{= !${device>/system/phone} &amp;&amp; !${app>/actionButtonsInfo/midColumn/fullScreen}}"
    icon="sap-icon://full-screen"
    type="Transparent"
    press="toggleFullScreen" />
  <Button
    visible="{= !${device>/system/phone} &amp;&amp; ${app>/actionButtonsInfo/midColumn/fullScreen}}"
    icon="sap-icon://exit-full-screen"
    type="Transparent"
    press="toggleFullScreen" />
  <Button
    icon="sap-icon://decline"
    type="Transparent"
    press="onCloseDetailPress" />
</headerContent>

In our BusinessPartnerDetail.view.xml and BusinessPartnerList.view.xml add three buttons to handle these features:

  • Expand to full-screen the current page
  • Exit full-screen
  • Close the current page (like a nav back click)

Those buttons will be only displayed if your application is not run on a mobile device (on a smartphone the page layout is already fully expanded).

On the Controller side, you just need to implement those methods like this

/////////////////////////////////////////////////////////
// LAYOUT EVENTS
/////////////////////////////////////////////////////////

/**
 * Set the full screen mode to false and navigate to master page
 */
onCloseDetailPress: function () {
	var oModel = this.getView().getModel("app");
	oModel.setProperty("/actionButtonsInfo/midColumn/fullScreen", false);
	this.getOwnerComponent().getRouter().navTo("TargeteBusinessPartnerList", {}, true);
},

/**
 * Toggle between full and non full screen mode.
 */
toggleFullScreen: function () {
	var oModel = this.getView().getModel("app");
	var bFullScreen = oModel.getProperty("/actionButtonsInfo/midColumn/fullScreen");
	oModel.setProperty("/actionButtonsInfo/midColumn/fullScreen", !bFullScreen);
	if (!bFullScreen) {
		// store current layout and go full screen
		oModel.setProperty("/previousLayout", oModel.getProperty("/layout"));
		oModel.setProperty("/layout", "MidColumnFullScreen");
	} else {
		// reset to previous layout
		oModel.setProperty("/layout",  oModel.getProperty("/previousLayout"));
	}
}

If you remember we have bound our FlexibleColumnLayout’s property in App.view.xml to the value of app>/layout

To expand full-screen a page we’re going to change that value to MidColumnFullScreen (this code is from the middle page Controller) and back to TwoColumnsMidExpanded or ThreeColumnsEndExpanded (it depends if we’re also displaying the third column) when the user exit fullscreen.

The close button is handled by the onCloseDetailPress button that will simply transition our application to the home page.

Step 4 — Enjoy the final result (without the Dynamic Page Layout)

If you want, you can clone the project and try it on your own. Check it out on my GitHub account.

After following all these steps this will be the final result. Do you see the differences between this video and the first one at the start of the blog post?

PS: the animations are not very smooth but I think that the issue could be my current laptop and the number of chrome tabs currently opened (+ all the IDEs that are eating my RAM)

What’s next

In the next blog post, we will bring our application to the next level removing all the sap.m.Page and replacing them with the new sap.f.DynamicPage

Feedback needed

What do you think about this series? Do you want more focus on some specific SAPUI5 aspect?

Write it down on the comment section! Happy coding to everyone!

2 Comments
You must be Logged on to comment or reply to a post.
  • Hi Emanuele Ricci,

    A small request Can you as well show us an example of dynamic page having the standard variant and filter bar on single screen.

    Thanks

    • Hi Manasa Sanga, unfortunately, the Variant Manager needs also a connected backend to correctly handle it.

      Maybe it could write about it in another blog post but I’ve still to finish this series 😉

      For the Dynamic Page, you just need to wait next week 😉