Implementing and Instantiating XML Fragments

Objective

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.

Sample XML fragment code, as described in the text.

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.

Screenshot highlighting the core:Fragment line.

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.

Steps for fragment instantiation: In a controller, use `loadFragment()`. In a non-controller artifact, use `sap.ui.core.Fragment.load()`.

If a fragment is to be instantiated within a view controller (more precisely, in a controller that extends sap.ui.core.mvc.Controller), the loadFragment method can be used. It is available in any view controller. The method passes to the created fragment the view controller as fragment controller. That is, the (event handler) methods referenced in the fragment are called on the view controller.

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

Outside of controllers, the generic method sap.ui.core.Fragment.load can be used for instantiation. Among other things, this method can be passed a JavaScript object that is to be used as a fragment controller. Any object can act as a fragment controller here, provided it has the methods required by the fragment.

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.

Screenshot of the dialog.fragment.xml file.

The figure, Dialog as XML Fragment, shows a simple dialog defined using an XML fragment.

The root control of the fragment is a sap.m.Dialog UI element. This control is used to prompt the user for an action or confirmation. When the dialog is opened in the application, it interrupts the current application processing because it is the only focused UI element and the main screen is blocked.

The content of a dialog is fully customizable and is defined using the content aggregation. In the example, for simplicity, the dialog contains only a Text UI element with the text Hello World.

The beginButton aggregation can be used to define an action button that will be displayed in the footer area of the dialog. In the example, it is a button with the text Ok, whose press event is bound to the event handler onCloseDialog.

The dialog will later be instantiated via a view controller, where the view controller will be set as fragment controller. This means that the view controller must have a method onCloseDialog, which will be used to close the opened dialog.

The value dialog is specified for the id attribute of the Dialog UI element in the example. This Id will later be used to access the created dialog instance in the view controller.

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.

Sample opening and closing dialog codes, as discussed in the text.

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.

Screenshot of the code for the sap/ui/core/syncStyleClass function, as discussed in the following text.

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.