Show TOC

Step 16: Dialogs and FragmentsLocate this document in the navigation structure

In this step, we will take a closer look at another element which can be used to assemble views: the fragment.

Fragments are light-weight UI parts (UI subtrees) which can be reused but do not have any controller. This means, whenever you want to define a certain part of your UI to be reusable across multiple views, or when you want to exchange some parts of a view against one another under certain circumstances (different user roles, edit mode vs read-only mode), a fragment is a good candidate, especially where no additional controller logic is required.

A fragment can consist of 1 to n controls. At runtime, fragments placed in a view behave similar to "normal" view content, which means controls inside the fragment will just be included into the view’s DOM when rendered. There are of course controls that are not designed to become part of a view, for example, dialogs.

But even for these controls, fragments can be particularly useful, as you will see in a minute.

We will now add a dialog to our app. Dialogs are special, because they open on top of the regular app content and thus do not belong to a specific view. That means the dialog must be instantiated somewhere in the controller code, but since we want to stick with the declarative approach and create reusable artifacts to be as flexible as possible, and because dialogs cannot be specified as views, we will create an XML fragment containing the dialog. A dialog, after all, can be used in more than only one view of your app.

Preview
Figure 1: A dialog opens when the new “Say Hello With Dialog” button is clicked
Coding

You can view and download all files in the Explored app in the Demo Kit under Walkthrough - Step 16.

webapp/view/HelloPanel.view.xml
<mvc:View
   controllerName="sap.ui.demo.wt.controller.HelloPanel"
   xmlns="sap.m"
   xmlns:mvc="sap.ui.core.mvc">
   <Panel
      headerText="{i18n>helloPanelTitle}"
      class="sapUiResponsiveMargin"
      width="auto" >
      <content>
      <Button
         text="{i18n>openDialogButtonText}"
         press="onOpenDialog"
         class="sapUiSmallMarginEnd"/>

      <Button
         text="{i18n>showHelloButtonText}"
         press="onShowHello"
         class="sapUiDemoWTmyCustomButton"/>
      <Input
         value="{/recipient/name}"
         valueLiveUpdate="true"
         width="60%"/>
      <Text
         text="Hello {/recipient/name}"
         class="sapUiSmallMargin sapThemeHighlight-asColor sapUiDemoWTmyCustomText"/>
      </content>
   </Panel>
</mvc:View>

We add a new button to the view to open the dialog. It simply calls an event handler function in the controller of the panel’s content view.

webapp/view/HelloDialog.fragment.xml (New)
<core:FragmentDefinition
   xmlns="sap.m"
   xmlns:core="sap.ui.core" >
   <Dialog
      title="Hello {/recipient/name}">
   </Dialog>
</core:FragmentDefinition>

We add a new XML file to declaratively define our dialog in a fragment. The fragment assets are located in the core namespace, so we add an xml namespace for it inside the FragmentDefinition tag.

The syntax is similar to a view, but since fragments do not have a controller this attribute is missing. Also, the fragment does not have any footprint in the DOM tree of the app, and there is no control instance of the fragment itself (only the contained controls). It is simply a container for a set of reuse controls.

webapp/controller/HelloPanel.controller.js
sap.ui.define([
   "sap/ui/core/mvc/Controller",
   "sap/m/MessageToast"
], function (Controller, MessageToast) {
   "use strict";
   return Controller.extend("sap.ui.demo.wt.controller.HelloPanel", {
      onShowHello : function () {
         …
      },
      _getDialog : function () {
         if (!this._oDialog) {
            this._oDialog = sap.ui.xmlfragment("sap.ui.demo.wt.view.HelloDialog");
            this.getView().addDependent(this._oDialog);
         }
         return this._oDialog;
      },
      onOpenDialog : function () {
         this._getDialog().open();
      }
   });
});

The internal _getDialog helper function is instantiating the fragment by calling the sap.ui.xmlfragment method with the path to the fragment definition as an argument. The function returns the instantiated controls for further use in the app. In our case this is the dialog that we would like to open.

We store the reference to the dialog in a private property on the controller to be able to open the same instance again when another user action is triggered (lazy instantiation with a singleton), and we add the fragment as "dependent" on the view to be connected to the view’s model lifecycle. A convenient side-effect is that the dialog will automatically be destroyed when the view is destroyed. Otherwise, we would have to destroy the dialog manually to free its resources.

webapp/i18n/i18n.properties
# App Descriptor
appTitle=Hello World
appDescription=A simple walkthrough app that explains the most important concepts of SAPUI5

# Hello Panel
showHelloButtonText=Say Hello
helloMsg=Hello {0}
homePageTitle=Walkthrough
helloPanelTitle=Hello World
openDialogButtonText=Say Hello With Dialog
dialogCloseButtonText=Ok

The text bundle is extended by two new texts for the open button and the dialog’s close button.

Conventions
  • Always use the addDependent method to connect the dialog to the lifecycle management and data binding of the view, even though it is not added to its UI tree.

  • Private functions and variables should always start with an underscore.