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: 
31,249
When we are going to create a huge SAPUI5 app with many huge views, splitting the huge views is one of the most important principles in design and implementation.

We can easily move some part of a view inside a XML fragment like the following:
<core:FragmentDefinition xmlns="sap.m" xmlns:l="sap.ui.layout" xmlns:core="sap.ui.core"
controllerName="com.mjzsoft.FragmentTest.controller.Part1"> <!-- This part is redundant -->
<VBox>
<items>
<Text text="This part is from XML fragment"/>
<Button text="Call Function of Fragment" press=".Part1.onClick"/>
<Button text="Call Function of Parent Directly" press="onClick"/>
</items>
</VBox>
</core:FragmentDefinition>

And we can add it in another XML file like the following:
<mvc:View controllerName="com.mjzsoft.FragmentTest.controller.View1" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mvc="sap.ui.core.mvc"
displayBlock="true" xmlns="sap.m" xmlns:l="sap.ui.layout" xmlns:core="sap.ui.core">
<App id="idAppControl">
<pages>
<Page title="{i18n>title}">
<content>
<l:VerticalLayout>
<l:content>
<core:Fragment fragmentName="com.mjzsoft.FragmentTest.view.Part1" type="XML"
id="prefix1"/>
<!--By using id you can add a fragment multiple times as it is used as a prefix in elements id-->
</l:content>
</l:VerticalLayout>
</content>
</Page>
</pages>
</App>
</mvc:View>

But normally this is not enough and the event handler of the elements inside the fragments (like the buttons) will not call the functions inside the fragment's controller but it will call the functions inside the parents view (Here View1). So if we move some parts of the view into a fragment and inject it inside the parent view, we actually still need to move the functions from parent view controller to another controller.

If you use the fragment for dialog this code split is easier as we can pass the controller as soon as we  create the dialog.
// Dialog1 uses the functions inside the parent controller
var oDialog1 = sap.ui.xmlfragment("com.mjzsoft.FragmentTest.view.myDialogFragment",
this);
// Dialog2 uses the functions inside of its own passed controller "com.mjzsoft.FragmentTest.controller.myDialogFragment"
var oDialog2 = sap.ui.xmlfragment("com.mjzsoft.FragmentTest.view.myDialogFragment",
"com.mjzsoft.FragmentTest.controller.myDialogFragment");

But what if we want our fragment element inside the XML view also access its own controller and not the parent controller. Actually as we said already in first code box there is a line that is redundant in our fragment file. Actually this line controllerName="com.mjzsoft.FragmentTest.controller.Part1".

The reason is that it does not have any effect on where the elements are bind for their event handlers. To achieve this goad we have 2 options.

1) The first option is to create a variable in parent controller as an instance of the controller of the fragment. Actually something like the `Part1` in the following:
sap.ui.define([
"sap/ui/core/mvc/Controller",
"com/mjzsoft/FragmentTest/controller/Part1.controller"
], function (Controller, Part1) {
"use strict";
return Controller.extend("com.mjzsoft.FragmentTest.controller.View1", {
Part1: new Part1(this), // this pointer is window here and not the Controller
onInit: function () {

},
onClick: function (oEvent) {
console.log("I am in View1 Controller.");
}
});
});

By this technique the elements inside the XML fragment must call the functions of Part1 like this:
<Button text="Call Function of Fragment" press=".Part1.onClick"/>

if we remove .Part1. from the event handler name then it will call the functions inside the parent controller.

What are the pros and cons of this method?


Pros: We can call functions of both controller.

Cons: We cannot access the fragment controller object inside the parent controller. While we have defined Part1 variable in parent controller but it seems we will have 2 Part1 variables. One is created at the time the view is created and fragment elements are bound to that. And one other which is accessible by this.Part1 in the parent controller while is different from the one that elements are bound to.

If you like to download the whole code regarding this method you can access our github. Check the github for latest code.

Here is an example of what has been printed in console by pressing on the buttons.



 

2) The second option is to generate that part of the view in the onInit function and then inject it in the desired container or element:
onInit: function () {
//Create new fragment with own controller
var oFragmentController = new FragmentController(this);
var oFragment = sap.ui.xmlfragment("com.mjzsoft.FragmentTest.view.Part1", oFragmentController);
this.getView().byId("myContainer").addContent(oFragment);
console.log(oFragmentController);
}

 

What are the pros and cons of this method?


Pros: We can call functions of both controller by passing the this pointer of the parent controller and set it as a class variable inside the controller. Please note for this we need to define a constructor inside the fragment controller.

Cons: We cannot directly access the functions inside the parent controller in the fragment XML file.
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function (Controller) {
"use strict";
return Controller.extend("com.mjzsoft.FragmentTest.controller.Part1", {
parent: null,
onInit: function () {
console.log("onInit of fragment will not call.");
},
onAfterRendering: function () {
console.log("onAfterRendering of fragment will not call.");
},
onClick: function (oEvent) {
console.log("I am in fragment controller");
},
constructor: function(oArg){
console.log("The fragment controller has been made");
console.log("You can pass some Argument to be set!!!", oArg);
this.oParent = oArg;
return Controller.call(this);
}
});
});
9 Comments
former_member277448
Participant
hello

thank you for this article.

this something i have been thinking about for some time - best way to break up a large view.

i have been thinking about using nested views rather than frafments. in this way the control is a module - everything is self contained and therefore reusable.

any thoughts appreciated.

cheers

pat
ArnaudBuchholz
Product and Topic Expert
Product and Topic Expert
0 Kudos
I recommend the nested view approach as it enforces modularity and avoids the 'spaghetti code' effect. If you need to pass information between controllers, use the event bus.

Those two patterns will make the code easier to maintain and more testable.
What we suggested here is more or less nested view, just we explained more and with more details. It will never make the spaghetti code even prevent that. Makes the code clear and you don't need to use event bus because you access to the parent controller. As I tested event bus, when we use the event bus we will not access to the same copy of the controller object. Actually we are accessing to a new copy of the targeted controller.
rafael_menezes
Explorer
0 Kudos
What if we have more than one level in the hierarchy?

On the "grandson" level, I ended up registering the event with 2 levels. I mean, something like this:




view 1 (with controller Controller) Button press="onClick()"

Controller1: frgSonController1 = new Controller1Son()

view 2 (with controller Controller1Son) Button press=".frgSonController1Son.onClick()"

Controller1Son: frgSonController1Son = new  Controller1SonSon()

view 3 (with controller Controller1SonSon) Button press=".frgSonController1.frgSonController1Son.onClick()"





But I wouldn't like to couple the view 3 controller with the view 1 controller.

Thanks in advance,

Rafael M.
0 Kudos

¿How to get control using byId in fragment handler?

Thanks,

Cleyderman G.

rangam
Explorer
0 Kudos
You can use sap.ui.core.Fragment.byId("<fragmentId>", "<controlId>").

 

Ranga
rangam
Explorer
Thanks for the post mjzsoft
boghyon
Product and Topic Expert
Product and Topic Expert
chris_nace
Explorer

There's no official documentation about a class named "FragmentController". Similarly, in a XML fragment, I don't think that a "FragmentDefinition" tag can hold a "controllerName" attribute.

That's no surprising since Fragments do not have controllers.

In my opinion, Fragments are a great way to display a set of controls with miminum interaction. They could also be reused (so it's important that their logic remain simple). You can pass an object containing callbacks routines in one of the parameters of sap.ui.core.Fragment.load().

For breaking a large view, I would definitively go for the nested views approach. Each view contains its own logic. The views communicate thanks to the event bus of the owner component.

Labels in this area