Implementing and Instantiating XML Fragments

Objectives

After completing this lesson, you will be able to:

  • Work with dialogs defined as XML fragment

Reusable UI Parts

UI parts that are to be used in several views cannot be easily defined. They either have to be created as new controls, or they have to be created as views. Creating them as new controls results in a development overhead, while creating them as separate views results in a runtime overhead.

To solve this problem, fragments were introduced. They support reuse and view modularization without adding overhead.

Watch this video to learn more about the main characteristics of fragments.

Note
Instead of defining fragments in a separate file, they can also be defined inline and instantiated immediately. In general, however, the inline definition of fragments plays only a minor role.

XML Fragments

Only XML fragments are covered in this course because they are the most common. For JavaScript fragments and HTML fragments, see the documentation.

XML fragments are similar to XML views, but have no <View> tag as root element.

An example for the definition of an XML fragment is shown in the figure Simple XML Fragment.

The file containing the definition of an XML fragment has the extension *.fragment.xml. It is loaded by the SAPUI5 runtime via its SAPUI5 module name (see below).

In the example, the <core:FragmentDefinition> tag is used as the root element of the fragment. Without this <core:FragmentDefinition> tag, the fragment would contain the Text control and the Button control as root controls. However, this is not possible because XML documents must always have exactly one root node.

The <core:FragmentDefinition> tag has no representation in HTML at runtime; its child elements are added directly where the fragment is placed.

In cases where the fragment contains only one root control, the use of the <core:FragmentDefinition> tag is optional.

The press event of the button in the example is bound to the event handler onDoSomething of a controller. This means that this fragment must be instantiated with a controller that has this method.

Fragment Instantiation

Instantiating Fragments in XML Views

The example in the figure, Declarative Use of Fragments, displays an XML view that includes the XML fragment shown above via the <core:Fragment> tag.

The fragmentName attribute of this tag contains the SAPUI5 module name of the fragment used.

The type attribute is used to pass the type of the fragment. This means that fragments of any type can be embedded in an XML view, not only XML fragments, but also JavaScript and HTML fragments.

With the help of the optional id attribute an Id for the fragment instance can be passed. This Id is used as a prefix for the Ids of all controls in the fragment instance. This way, duplicate id errors can be avoided if a fragment is embedded twice in the same view, for example.

Note
For details regarding unique Ids, see the documentation.

The implemented fragment reference ultimately works like an import statement that includes the fragment's content controls into the view.

When a fragment is embedded in an XML view, the view's controller is automatically set as the fragment's controller as well. Since in the example discussed here the fragment contains a button whose press event is bound to the event handler onDoSomething, this method must be present in the controller of the embedding view.

Instantiating Fragments via API

SAPUI5 provides two options to instantiate fragments via API.

An example of the use of loadFragment will be discussed later.

For more information on the two methods mentioned, see the API Reference in the Demo Kit.

Dialogs as Fragments

Dialogs are special because they open on top of the regular application content and thus do not belong to a special view. In addition, dialogs can be used in more than one view of an application.

Views do not support the implementation of such dialogs, but fragments are very suitable for defining dialogs and other popup controls that are not part of the normal page UI structure.

To use fragments for defining popups, just let the fragment's root control be a dialog or similar control.

Using Dialogs Defined as Fragments

In order to open the dialog shown above in a view controller, the corresponding fragment must first be loaded.

This can be done using the loadFragment method, which is available in any view controller (see above). The anyControllerMethod in the figure Opening and Closing a Dialog shows how the loadFragment method can be used.

The loadFragment method is passed the module name of the fragment to be loaded (in the example sap.training.exc.view.Dialog). By default, loadFragment assumes that the fragment is an XML fragment. Other fragment types can be passed to the method via the property type.

The loadFragment method returns a Promise that resolves with the fragment content, that is, with the Dialog instance. In the example, the Promise pDialog returned by loadFragment is stored as a controller property (this.pDialog). With the help of this controller property, the if statement ensures that the loadFragment method is called only once, the first time anyControllerMethod is processed. This is because after the first processing of anyControllerMethod, this.pDialog is no longer initial and thus the if block is no longer processed.

As said, the Promise resolves with the fragment content, that is, with the Dialog instance. On this Dialog instance, the open method is called to open the dialog.

The loadFragment method passes the view controller as fragment controller to the loaded fragment. The event handler onCloseDialog referenced by the button in the XML fragment in the example must therefore be implemented on the view controller (see figure Opening and Closing a Dialog).

The loadFragment method ensures that the Ids used in the fragment are prefixed with the Id of the view instance to avoid duplicate Id issues. This leads to the fact that the controls used in the fragment can be accessed via the byId method of the controller. For this purpose, the control Id assigned in the fragment is passed to the byId method. In the example, the created Dialog instance is accessed in this way and the close method is called on it to close the open dialog again.

Synchronizing the Content Density

A dialog is opened in a special part of the DOM called the static area. Thus, it is not part of the view through which it is opened. As a result, the content density CSS class set for the view is not automatically forwarded to the dialog. The corresponding style class of the view must therefore be passed to the dialog manually.

The sap/ui/core/syncStyleClass function can be used to do this, as shown in the figure Forwarding the Content Density to a Dialog.

In the figure, the sap/ui/core/syncStyleClass function has been added to the dependency array of the corresponding view controller and the factory function has been extended by the parameter syncStyleClass.

The synchronization of the style class is done in the method anyControllerMethod, which is used to load the XML fragment and open the dialog, as described above. In order to pass the content density to the dialog, the highlighted coding has been added to this method.

The added code registers a callback function that is executed when the loading of the fragment could be completed successfully. The dialog instance is passed to this callback function.

By calling the bind method on the added callback function, it is achieved that the this keyword in the implementation of the callback function has the value which is passed to the bind method. That is, this references the view controller within the callback function.

In the callback function, the sap/ui/core/syncStyleClass function is used to apply the content density set for the view to the dialog instance. For this purpose, the content density currently used in the application is queried via the getContentDensityClass method of the component controller.

Note
The getContentDensity method must have been created by the developer beforehand and implemented accordingly (see above).

For details on how to use the sap/ui/core/syncStyleClass function, see the API Reference in the Demo Kit.

In order to chain the then method, the callback function returns the dialog instance oDialog. This ensures that this instance is passed to the next registered fulfill callback.

Implement a Popup Using a Fragment

Business Scenario

In this exercise, you will implement a popup with an info text and an Ok button to close it using an XML fragment. The dialog box should be displayed when the user presses the Create Customer button on the Overview view. You will apply the content density CSS class that you set in the previous exercise to the dialog box as well.

Template:Git Repository: https://github.com/SAP-samples/sapui5-development-learning-journey.git, Branch: sol/9_content_density
Model solution:Git Repository: https://github.com/SAP-samples/sapui5-development-learning-journey.git, Branch: sol/10_fragments

Task 1: Create an XML Fragment with the Definition of the Dialog Box

Steps

  1. Create a new file named Dialog.fragment.xml in the subfolder view of the webapp folder.

    1. Open the context menu for the webapp/view folder in the project structure.

    2. Select New File.

    3. In the New File dialog that appears, type Dialog.fragment.xml and choose OK.

    Result

    The Dialog.fragment.xml file is created and displays in the editor.
  2. Add the following code to the Dialog.fragment.xml file to define a dialog box using the XML fragment:

    Code snippet
    <core:FragmentDefinition
      xmlns="sap.m"
      xmlns:core="sap.ui.core">
      <Dialog
        id="dialog"
        title="Info" type="Message">
          <content>
            <Text text="Customer data is later saved via an OData service."/>
          </content>
          <beginButton>
            <Button
              text="Ok"
              press=".onCloseDialog"/>
          </beginButton>
      </Dialog>
    </core:FragmentDefinition>
    Copy code
    Note
    The dialog box displays the text "Customer data is later saved via an OData service" to the user. In addition, it has an Ok button that the user can use to close the popup again. For this purpose, the event handler method onCloseDialog registered for the press event of the Ok button will be implemented later. Please also note the Id dialog of the sap.m.Dialog UI element. This Id will be used later in the onCloseDialog event handler method to access the popup.

Result

The XML fragment should be implemented as follows:

Task 2: Register an Event Handler for the press Event of the Button on the Overview View

Steps

  1. Open the Overview.view.xml file from the webapp/view folder in the editor.

  2. Add attribute press=".onSave" to the <Button> tag of the Create Customer button to register an event handler named onSave on the press event of this button.

    Note
    In the next step, you will implement this event handler on the view controller to open the popup created above.

Result

The Create Customer button should now be implemented as follows:

Task 3: Implement the Registered Event Handler on the View Controller to Open the Popup

Steps

  1. Open the Overview.controller.js file from the webapp/controller folder in the editor.

  2. Add the onSave event handler method registered with the Create Customer button in the previous step to the view controller. Implement this method as follows to open in it the popup defined above:

    Code snippet
    onSave: function () {
      if (!this.pDialog) {
        this.pDialog = this.loadFragment({
          name: "sap.training.exc.view.Dialog"
        });
      }
      this.pDialog.then(function (oDialog) {
        oDialog.open();
      });
    }
    Copy code
    Note

    If the dialog in the fragment does not exist yet, the fragment is instantiated by calling the loadFragment() method.

    The loading Promise of the dialog fragment is stored on the view controller instance. This makes it possible to handle the opening of the dialog asynchronously on each click of the Create Customer button.

Result

The view controller should now look like this:

Task 4: Implement the Method to Close the Dialog on the View Controller

Steps

  1. Make sure that the Overview.controller.js view controller is open in the editor.

  2. Add the onCloseDialog event handler method, registered above for the Ok button on the popup, to the view controller. Implement this method as follows to close the popup through it again:

    Code snippet
    onCloseDialog: function () {
      this.byId("dialog").close();
    }
    Copy code
    Note
    The event handler method closes the popup by accessing the dialog through its Id. It is not necessary to chain to the pDialog Promise, since the event handler is only called from within the loaded dialog itself.

Result

The view controller should now look like this:

Task 5: Apply the Content Density for the Dialog

Steps

  1. Make sure that the Overview.controller.js view controller is open in the editor.

  2. Add the sap/ui/core/syncStyleClass module to the dependency array of the view controller and a corresponding parameter named syncStyleClass to the factory function of the view controller.

    Result

    The view controller should now look like this:
  3. Use the sap/ui/core/syncStyleClass module in the onSave event handler method to forward the content density to the popup. To do this, adjust the implementation of the event handler method as follows:

    Code snippet
    onSave: function () {
      if (!this.pDialog) {
        this.pDialog = this.loadFragment({
          name: "sap.training.exc.view.Dialog"
        }).then(function (oDialog) {
          syncStyleClass(this.getOwnerComponent().getContentDensityClass(), this.getView(), oDialog);
          return oDialog;
        }.bind(this));
      }
      this.pDialog.then(function (oDialog) {
        oDialog.open();
      });
    }
    Copy code
    Note
    The popup is not part of the Overview view, but is opened in a special part of the DOM, the static area. Therefore, the content density class defined in the App view is not known to the popup, so the style class of the app is manually synchronized with the popup.

    Result

    The onSave event handler method should now look like this:
  4. Test run your application by starting it from the SAP Business Application Studio.

    Check the following points:

    • Make sure that the popup opens when you press the Create Customer button.
    • Make sure that the popup is closed when you press the Ok button on the dialog box.
    • Make sure that the content densities compact and cozy are passed through to the dialog box. The Ok button on the dialog box should be displayed larger for cozy than for compact.
    Note

    To test the different content densities, you can use the device toolbar in the developer tools of the Google Chrome, Firefox, or Microsoft Edge browser: Start your application and, in the developer tools (F12), call the device toolbar with the key combination Ctrl + Shift + M. You can use the device toolbar to select a device you want to emulate. After you select the device, you have to refresh the browser (F5), to ensure that the onInit() method of the App view controller is called, where the content density is set specifically for the device type.

    1. Right-click on any subfolder in your sapui5-development-learning-journey project and select Preview Application from the context menu that appears.

    2. Select the npm script named start-noflp in the dialog that appears.

    3. In the opened application, check if the component works as expected.

Log in to track your progress & complete quizzes