Skip to Content

Motivation

First time we develop complex UIs/Views in SAPUI5 could write 1000-2000 lines in a view. Table creations, forms, layouts, etc. could produce several lines of code. Also we want to standarize our components with same aspect, same styles, same button icons, etc.


SAPUI5 offers a simple mechanism to reuse code: Fragments (https://sapui5.netweaver.ondemand.com/sdk/#docs/guide/Fragments.html).

This blog describes a simple example to create two SAPUI5 tables with one Fragment and reuse table code creation.


NOTE: As of the initial release of Fragments in version 1.15.0 of SAPUI5, they are marked as experimental, so the API can change at any time and they are not guaranteed to work properly.

Step by step

1. Declare your new fragments package.

/wp-content/uploads/2014/01/fragments_1_364843.png

Remember load new fragment resources in your html file:


sap.ui.localResources("fragment");



2. Create a fragment

This fragment creates a table with data binding, different type columns, etc.


sap.ui.jsfragment("fragment.Table", {
    createContent: function(oController) {
       //Obtain data from controller
       var aData = oController.fragmentInitData.data;
       //Create an instance of the table control
       var oTable = new sap.ui.table.Table({
            title: oController.fragmentInitData.title, //Obtain title from controller
            visibleRowCount: 7
       });
       //Obtain column definition from controller
       for (var i=0; i<oController.fragmentInitData.columns.length; i++) {
            var template;
            //Define the columns and the control templates to be used
            if (oController.fragmentInitData.columns[i].type == "Text")
                 template = new sap.ui.commons.TextView().bindProperty("text", oController.fragmentInitData.columns[i].bindingPath);
            else if (oController.fragmentInitData.columns[i].type == "Rating")
                 template = new sap.ui.commons.RatingIndicator().bindProperty("value", oController.fragmentInitData.columns[i].bindingPath);
            else if (oController.fragmentInitData.columns[i].type == "Checkbox")
                 template = new sap.ui.commons.CheckBox().bindProperty("checked", oController.fragmentInitData.columns[i].bindingPath)
            if (template != undefined) {
                 oTable.addColumn(new sap.ui.table.Column({
                 label: new sap.ui.commons.Label({text: oController.fragmentInitData.columns[i].title}),
                 template:  template,
                 sortProperty: oController.fragmentInitData.columns[i].bindingPath,
                 filterProperty: oController.fragmentInitData.columns[i].bindingPath,
                 width: "200px"
            }));
       }
  }
  var oModel = new sap.ui.model.json.JSONModel();
  oModel.setData({modelData: aData});
  oTable.setModel(oModel);
  oTable.bindRows("/modelData");
  //Initially sort the table
  oTable.sort(oTable.getColumns()[0]);
  //Bring the table onto the UI
  return oTable;
    }
});


3. Use your new fragment

In this view, we reuse the previous fragment twice:


//Define some sample data
var aData = createSampleData();
//Define fragment init data
oController.fragmentInitData = {
       title: "This is a Table Fragment Example",
       data : aData,
       columns: [{title: 'Last Name', bindingPath: 'lastName', type: "Text"},
                            {title: 'Name', bindingPath: 'lastName', type: "Text"},
                            {title: 'Selected', bindingPath: 'checked', type: "Checkbox"},
                            {title: 'Rating', bindingPath: 'rating', type: "Rating"}]
   };
//Instantiate fragment.Table with this init data "oController.fragmentInitData"
var table1 = sap.ui.jsfragment("fragment.Table", oController);
//Define some sample data again
var aData2 = createSampleData();
//Define fragment init data. Different init data this time (different title and less columns).
oController.fragmentInitData = {
       title: "This is a Table Fragment Example 2",
       data : aData,
       columns: [{title: 'Last Name', bindingPath: 'lastName', type: "Text"},
                            {title: 'Name', bindingPath: 'lastName', type: "Text"}]
   };
//Instantiate fragment.Table with this init data "oController.fragmentInitData"
var table2 = sap.ui.jsfragment("fragment.Table", oController);
var oDivider1 = new sap.ui.commons.HorizontalDivider("divider1");
oDivider1.setHeight(sap.ui.commons.HorizontalDividerHeight.Large);
//Present data into VerticalLayout
var oLayout = new sap.ui.layout.VerticalLayout({
       content: [table1, oDivider1, table2]
})



Result

/wp-content/uploads/2014/01/fragments_2_364842.png

EDIT: JSBin Example

We could reuse our JS code with functions (for example: createTable()), protyping “classes”, etc. This is a different SAPUI5 standard way to create common Fragments to be reused in our apps as the same way with “Views”.

Enjoy! 😉

To report this post you need to login first.

12 Comments

You must be Logged on to comment or reply to a post.

  1. Marco Voelz

    Dear Angel,

    thanks for the great introduction to fragments, this looks really useful! Just a quick question: Why do you create the data which you pass to the fragment as a property of the controller? Couldn’t you just pass the ‘fragmentInitData’ into the fragment’s constructor?

    Warm regards

    Marco

    (0) 
    1. Angel Puertas Post author

      Thanks Marco,

      I’ve tried passing fragmentInitData on fragment constructor but I haven’t found other way to instantiate fragment than this:

      var table2 = sap.ui.jsfragment(“fragment.Table”, oController);

      Fragment constructor receives oController on creation. I’ve cloned JSBin code, if you could suggest how we could acchieve this, it will be very useful:

      JS Bin – Collaborative JavaScript Debugging

      Thanks!

      (0) 
        1. Angel Puertas Post author

          Thanks Marco! It’s interesting know that works.

          An appreciation I think this example is working because as I think JS is a typeless language, it is possible to facilitate fragmentIniData parameter instead of oController. But the purpose of Fragment.createContent method could require oController in order to interact with some methods or logic of your UI:

          SAPUI5 SDK – Demo Kit

          Defined in: <sap/ui/core/Fragment.js>.

          Parameters:

          {string} sName the Fragment name
          {string} sType the Fragment type, e.g. “XML”, “JS”, or “HTML”
          {sap.ui.core.Controller} oController?, Default: the Controller which should be used by the controls in the Fragment. Note that some Fragments may not need a Controller and other may need one – and even rely on certain methods implemented in the Controller.

          What do you think about it? May be I’m wrong

          Kind regards!

          (0) 
          1. Marco Voelz

            Dear Angel,

            I think you’re right – there might be a case where you need to pass the corresponding controller to the fragment. In your scenario, however, it just seems to introduce an indirection which you don’t need.

            Maybe it is a good idea to pass the controller when scenarios get more complicated and you need to handle events from the fragments with controller methods. So I guess there is no “right” and “wrong” here 😉

            Warm regards

            Marco

            (0) 
  2. Pavel Kultyshev

    Hi, one interesting question:

    assume that

    1) u have xml fragment with predefined control id

    2) u need to use it several times per view

    when u try to add second+ time the jsconsole shouts at u:

    Error: Error: adding element with duplicate id

    How did sapui5 manages this situation? it has the fragment system, but does not have the way control id’s are rendered in a correct way.

    What can we do in this situation?

    (0) 
  3. Marc Antunes

    Good example, but I’m still struggling with the use of the same fragment with two views; this get me the error of ‘duplicate IDs’ of the inner variables..

    tried to use the destroy, but doesn’t fix the issue..

    Anyone know what is the canonical process to do this?

    (0) 
    1. Angel Puertas Post author

      Hi Marc,

      Avoid using ids on fragments, or pass a parameter in order to create the IDs dependant on prefixes eg: prefix + ‘_my_text_inside_fragment’.

      Hope this helps,

      Kind regards

      (0) 
      1. Marc Antunes

        Hi,

        thank you for the reply Angel,

        So, I can’t use a fragment as a commum method over diferents view..?

        That leads me to code replication and all its issues.. =/

        (0) 

Leave a Reply