Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
WouterLemaire
Active Contributor
Hi UI5 Developers,

 

Introduction


In UI5 we can use fragments to split up a view in small pieces which you can reuse in other views. These fragments mainly contain parts of the UI and can be called from in a View or controller. When calling/opening a fragment you can also add a controller to this fragment, like for example in this blog:

https://blogs.sap.com/2015/05/21/use-of-fragments-in-sapui5-reusability/

I tried this out and noticed that the behavior, of the controller that we add to a fragment, is not the same as a normal controller of a view. You cannot use this.getModel( ) or this.getView( ), “this” is not a reference to the fragment… For that reason I’ve created a function in my baseController that opens fragments with some added features.

In this blog I explain when I add a controller to a fragment, why I’m doing this and I will explain how my function works.

When?


I would not always add a controller to a fragment. I would only (or most of the time) do this when my fragment contains a dialog. I put all my dialogs in fragments. This gives me a good overview of all the dialogs in my project. You could also create a dialog using JavaScript but it’s hard to maintain in large projects.

Why?


This brings me to the why. Why would I want to add a controller to a fragment (containing a dialog)? There are a few reasons why:

  1. Organized project

  2. A dialog should contain his own logic to have his own lifecycle

  3. It enables us to re-use the fragment but also the logic behind the fragment

  4. Less code in the controller of the view from where the fragment is called

  5. Better organization of your coding


How?


I created a generic function in my baseController to open fragments. In this function I’ve added a few parameters:

  • Name: name of the fragment (and controller)

  • Model: option to pass a model from the view where it’s called (optional)

  • updateModelAlways: let the function know if it has to update the model every time it opens the dialog or only the first time.

  • callback: a function in the controller from where it’s called which can be executed from the fragment controller

  • data: pass information from the main view to the fragment


The function will also create a controller if it can find one in the controller folder. The folder structure in the controller folder must be the same as in the view folder. If the function finds a controller and it’s not the current controller then it will call an onbeforeshow function in this controller. The onbeforeshow is comparable to the onRouteMatched function in a view. It will be called just before it opens the dialog to do some initialization.

The function:
openFragment: function(sName, model, updateModelAlways, callback, data) {
if (sName.indexOf(".") > 0) {
var aViewName = sName.split(".");
sName = sName.substr(sName.lastIndexOf(".") + 1);
} else { //current folder
aViewName = this.getView().getViewName().split("."); // view.login.Login
}
aViewName.pop();
var sViewPath = aViewName.join("."); // view.login
if (sViewPath.toLowerCase().indexOf("fragments") > 0) {
sViewPath += ".";
} else {
sViewPath += ".fragments.";
}
var id = this.getView().getId() + "-" + sName;
if (!_fragments[id]) {
//create controller
var sControllerPath = sViewPath.replace("view", "controller");
try {
var controller = sap.ui.controller(sControllerPath + sName);
} catch (ex) {
controller = this;
}
_fragments[id] = {
fragment: sap.ui.xmlfragment(
id,
sViewPath + sName,
controller
),
controller: controller
};
if (model && !updateModelAlways) {
_fragments[id].fragment.setModel(model);
}
// version >= 1.20.x
this.getView().addDependent(_fragments[id].fragment);
}
var fragment = _fragments[id].fragment;
if (model && updateModelAlways) {
fragment.setModel(model);
}
if (_fragments[id].controller && _fragments[id].controller !== this) {
_fragments[id].controller.onBeforeShow(this, fragment, callback, data);
}

setTimeout(function() {
fragment.open();
}, 100);
}

I also created a function to get a control from in the fragment. This is different than in a view, it’s a combination of the view id, fragment id and the control id. The fragment id is something I’ve added in my function for opening the fragment.
getFragmentControlById: function(parent, id) {
var latest = this.getMetadata().getName().split(".")[this.getMetadata().getName().split(".").length - 1];
return sap.ui.getCore().byId(parent.getView().getId() + "-" + latest + "--" + id);
}

This function can be used like this:
var label = this.getFragmentControlById(this.parent,"label1");

Last but not least I have a function for closing all the fragments . This makes it easy for a close button in each fragment. It just calls this function and it will close the open fragments. (In case the fragment contains a dialog.)
closeFragments: function() {
for (var f in _fragments) {
if (_fragments[f]["fragment"] && _fragments[f].fragment["isOpen"] && _fragments[f].fragment.isOpen()) {
_fragments[f].fragment.close();
}
}
}

Now I can open a fragment from each controller like this:
this.openFragment(
"Demo1",
null,
true,
this.onFragmentCallback, {
title: "Fragment Demo"
}
);

And I can handle the moment that it closes with the callback function:
onFragmentCallback: function() {
MessageToast.show("Back in controller");
}

I use this almost in each UI5 project and it already helped me a lot. Hope it helps others or become part of the standard baseController 🙂

You can find a live demo on github:

https://rawgit.com/lemaiwo/SAPUI5Fragments/master/webapp/index.html

Source code:

https://github.com/lemaiwo/SAPUI5Fragments

 

Kind regards,

Wouter Lemaire
2 Comments
Labels in this area