In the first part of this blog we focused on generating a business application using the SAP Web IDE. Our application displays business data retrieved from the public OData Northwind service. Then we deployed the application to our HANA Cloud Platform account , registered it to our newly created Fiori Launchpad Site and created a Static Tile for it.

In the 2nd part of this blog we will see how to create Dynamic and Custom Launch Tiles for our employees application (section 4 and 5) and dive into some of the implementation details related to the custom tile (section 6).

Creating a News Tile to display RSS feeds is described in this blog:

FIORI Launchpad in SAP HCP – news tiles and cross origin policy error

Creating a Mobile Docs Tile to display and access your documents is described in this blog:

Creating an SAP Mobile Documents Tile in SAP Fiori Launchpad on Cloud



4) Configuring a Dynamic Tile

Dynamic app launcher tiles can display a KPI number retrieved by an OData services. The tile has a configurable refresh interval for fetching new data. In this part we will create an additional (dynamic) tile for the employees application showing the number of employees.

Explanation Screen Shot

Create a new App Tile


  1. Go back to your Launchpads Configuration Cockpit
  2. Click on the Create App Tile tile
  3. In the general Properties screen enter the App Name = Employees (D)
  4. Click Next

/wp-content/uploads/2015/05/dynamictile1_696757.png

In the Navigation screen

  1. Insert the following values
    • App Type: SAPUI5

    • Component URL: /
      Is the relative path from you application root to your Component.js file
    • SAPUI5 Component Name: employees
      Is the registered name of the SAPUI5 component, defined in the Component.js file, without .Component
    • HTML5 App Name: employees
      Is the name of the deployed HTML5 application
  2. Click Next


/wp-content/uploads/2015/05/dynamictile2_696761.png

In the Tile screen


  1. Insert the following values under General
    • Type: Dynamic App Launcher
    • Size: 1 X 1
    • Title: Our Employees
    • Icon: Choose any icon

  2. Insert the following values under Dynamic Data
    • Number Unit: Active Employees
      Is the unit displayed below the KPI number

    • Service URL:

/sap/fiori/employees/destinations/northwind/V3/Northwind/
Northwind.svc/Employees/$coun
t
    
       
Is the URL of an OData query from which data should be read. The format of the URL is as follows:

/<fiori proxy>/<application id>/destinations/<destination name>/<path to OData service>/<OData collection>/<query string>

    • Refresh Interval: 6000
      Is the Number of seconds after which dynamic content is reloaded from the data source and the display is refreshed

  3. Click Next

/wp-content/uploads/2015/05/dynamictile3_696762.png
In the Assignment screen

  1. Assign your application to the Northwind Tile Group you created earlier
  2. Assign your application to the Northwind Content Package you created earlier.
  3. Click Finish


The new Tile should now be available on your launchpad Site

/wp-content/uploads/2015/05/dynamictile4_696763.png
Preview the Fiori launchpad Site

  1. Go back to the launchpad site

  2. Refresh the browser
  3. Notice the new Tile Group Northwind added to your launchpad with the new Dynamic Tile in it displaying the KPI (number of employees) defined by the OData query
/wp-content/uploads/2015/05/dynamictile5_696764.png



5) Developing a Custom Tile

Custom tiles can display any content that you define in an SAPUI5 view. This means that we can add additional Views (and Controllers) to our lightweight applications for the sake of creating custom tiles or deploy them as part of a separate dedicated application.

For that sake of this exercise, we already implemented the code required for the custom tile. It uses the same Northwind OData service we used for the employees app itself, this time displaying a kind of a business card teaser that switches between each of the available employees in a timed interval:

/wp-content/uploads/2015/05/customtile3_696768.png

You will need to download the source code (attached below), import it to your SP Web IDE project, commit the changes to the dedicated git repository and create the new tile.

Explanation Screen Shot
  1. Download the 3 files attached at the end of this blog
    Formatter.js.txt.zip, Tile.controller.js.txt.zip,  Tile.view.xml.txt.zip

  2. Rename the files to: Formatter.js, Tile.controller.js,  Tile.view.xml

Import the code into your Web IDE employees project


  1. Expand the employees root folder
  2. Right click on the view folder
  3. Select Import > From File System
  4. From the Import dialog box click Browse…
  5. Select the Tile.controller.js file
  6. Click OK
  7. Import Tile.view.xml into the view folder
  8. Import Formatter.js into the util folder



/wp-content/uploads/2015/05/customtile1_696766.png
Your employees project should have the following file structure /wp-content/uploads/2015/05/customtile2_696767.png

Commit the new files to the Git Repository


  1. Select the employees root project folder
  2. Open the Git Pane from the right side panel.
  3. Click the Stage All check box.
    The 3 new files should all be staged for commit
  4. Insert a Commit Description
  5. Click on the Commit and Push button at the bottom
  6. Select the origin/master branch
  7. In the Authentication dialog box enter your SCN credentials
  8. Click OK
/wp-content/uploads/2015/05/customtile4_696773.png

Create a new application version and activate it


  1. Open your HANA Cloud Platform Cockpit
  2. Select HTML5 Applications from the left side content panel
  3. Select the employees application from your list of HTML5 apps to open the applications Dashboard
  4. Select Versioning from the left side panel
    Notice your latest commit is at the top of the list
  5. Click on the latest commit’s Action button to create a version from it
  6. Enter a Version Name (ex 1.1)
  7. Click Save
  8. Click on the latest commits Action button again to activate and publish it

/wp-content/uploads/2015/05/customtile5_696774.png

/wp-content/uploads/2015/05/customtile6_696779.png

Now that we deployed and published the latest version of our application we can go back and create the tile.

Explanation Screen Shot

Create a new App Tile

  1. Go back to your Launchpads Configuration Cockpit
  2. Click on the Create App Tile tile
  3. In the General Properties screen enter the App Name = Employees (C)
  4. Click Next
/wp-content/uploads/2015/05/dynamictile1_696757.png

In the Navigation screen – Same as in Part 4.

  1. Insert the following values
    • App Type: SAPUI5
    • Component URL: /
    • SAPUI5 Component Name: employees
    • HTML5 App Name: employees
  2. Click Next

In the Tile screen

  1. Insert the following values under General
    • Size: 1 X 2
    • Title: Employees (C)
    • Module Type: XML
      This value corresponds to the SAPUI5 View type you created for the custom tile
    • Module Name: employees.view.Tile
      The ID of the SAPUI5 View
    • Module Name Prefix: employees
      Is the app id in which the view is included
    • Module path: /sap/fiori/employees/
      Is composed of: <fiori proxy>/<app id>

Custom Properties, are a key-value pair that can be used in the tile’s source code. We use them in our implementation to set the tile’s header text. (See part 6 for more information)

  1. click Add to to add an additional Key-Value pair
  2. Insert  the following (case sensitive)
    • Key: titleText
    • Value: Colleagues you may know….
  3. Click Next
/wp-content/uploads/2015/05/customtile7_696935.png

In the Assignment screen – Same as in Part 4.

  1. Assign your application to the Northwind Tile Group you created earlier
  2. Assign your application to the Northwind Content Package you created earlier.
  3. Click Finish


The new Tile should now be available on your launchpad Site

Preview the Fiori launchpad Site

  1. Go back to the Launchpad site

  2. Refresh the browser
  3. Notice the new Custom Tile was added to the Northwind Tile Group
/wp-content/uploads/2015/05/customtile8_696936.png

6) Pointers for Implementing a Custom Tile

As we mentioned earlier a custom tile is basically a small application based on an SAPUI5 View and its corresponding Controller. Inthis section we will focus on some of the technical aspects of implementing one. You may want to take a look at our implementation for the Employees custom tile in the attached files you imported into your Web IDE:

  • employees.view.Tile.view.xml
  • employees.view.Tile.controller.js


a. Tile Content

the SAPUI5 library comes with several Tile implementations that are pretty easy and intuitive to use. In SAPUI5 Explore you can view the APIs, run some samples and view the code. You can use the Standard Tile or the Overview Tile. For the Employees custom tile we used the Generic Tile.

Another option is to use the Custom Tile which enables you to determine the tiles structure by using any SAPUI5 controls or standard HTML tags within the tile’s content tag:


<CustomTile xmlns=”sap.m”

  id=”customTile”

  class=”customTileStyle”

  press=”onPress”>

  <content>   

      <html:div class=”container” >

               <html:div class=”title_tile_home” id=”titleDiv” >

                        XXX TITLE

               </html:div>

                   <html:div class=”info_text_tile” id=”descriptionDiv”>

                    <html:div class=”counter_home” id=”counterDiv”>6 </html:div>

                    xxx description xxxx

               </html:div>

       </html:div>   

  </content>

</CustomTile>



b. Passing Parameters to the Tile

When we configured the Employees custom tile in section 5 we added a Custom Property (Key-Value pair). The cutome properties (and their values) are passed to the tile so we can make use of them in our code if we dont want to hardcode specific values (and leave them for the administrator to configure) or if we would like to reuse the tile and make it more generic.

To access the custom property titleText we configured in section 5 in our *.Controller.js:

var view = this.getView();

var oViewData = view.getViewData();

var titleTextValue = oViewData.properties.titleText;

c. Using Resources

In case you’d like to use additional resources (like image files) in your custom tile you need to include them in your application. In addition, in order to integrate your app into the Fiori Launchpad Site, you will need to modify the URLs youre using to reference these resources and add the module path prefix:

jQuery.sap.getModulePath(“< app id >”)


For instance, lets say we want to use an image ae.jpg to our custom tile.

/wp-content/uploads/2015/05/coding1_696977.png
  • Create a new img folder under the project root folder
  • Upload the image resource ae.jpg into it
  • The reference to use while developing and previewing the application in the Web IDE:
    “employees/img/ae.jpg”

  • The reference we would use for Fiori Launchpad integration:
    jQuery.sap.getModulePath(“employees”) + “/img/ae.jpg

d. Launching the Application

When developing a custom tile, you are also responsible for implementing the tile’s behavior upon a click / press event.

Generally, tiles usually launch the associated application upon a user press event, however tiles can also be used as standalone mini apps (such as an image gallery) that dont launch any application.

In order to launch the application associated with your custom tile upon press implement the following:

1. In the SAPUI5 View (take a look at the attached Tile.view.xml file) – declare a handler for your tile’s press event

    

<GenericTile

        id=”genericTile”

        class=”tile”

        size=”M”

        frameType=”TwoByOne”

        press=”onPress”>

  </GenericTile>


2. Implement the handler in the corresponding Controller (take a look at the attached Tile.controller.js file):

onPress: function(){

     var view = this.getView(),

     oViewData = view.getViewData(),

     navTargetUrl = oViewData.properties && oViewData.properties.navigation_target_url;

     if (navTargetUrl) {

         if (navTargetUrl[0] === ‘#’){

             hasher.setHash(navTargetUrl);

         }

         else{

             window.open(navTargetUrl, ‘_blank’);

         }

     }

}

The Launchpad navigation framework provides the hasher object for launching applications with a hashed URL.  The URL is available in the ViewData object that we used in (part b) for accessing our Custom Tile Properties and contains the tile’s own configuration properties.  The URL is stored under a property named navigation_target_url.

/wp-content/uploads/2015/05/coding2_697880.png

If the URL is hashed the application is launched within the Launchpad, otherwise it is opened in a new browser window.

To report this post you need to login first.

17 Comments

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

  1. Marcos Andrade

    Hello Ido,

    thank you for your blog. I can see you put a lot of effort on that. I will try to implement the custom tile and see how it goes.

    just a quick question, have you give the requirement to display a title dynamically?

    In my case I have the application input of absence which should be only available by people that has a certain employee group.

    how would I display it dynamically?

    (0) 
    1. Andre Friese

      Hi Michael,

      I encounter exactly the same issue. Try to reverse engineer it, but it seems like the setting you mentioned too, do not have an effect on the url for the tile.

      Did you solve the problem?

      Best regards

      Andre

      (0) 
      1. Guy Roth

        Hi Andre,

        Please try the following settings:

        Name: <appName>.view.GraphTile

        Prefix: <appName>.view

        Path: /sap/fiori/<appName>/view

        Regards,

        Guy

        (0) 
        1. Andre Friese

          Hi Guy,

          now it worked for me:

          Name: <appName>.view.GraphTile

          Prefix: <appName>

          Path: /sap/fiori/<appName>

          The problem was that the namespaces in the Tile-relevant files (view.xml and controller.js) did not match the appName.

          <core:View xmlns:core=”sap.ui.core”

            xmlns:mvc=”sap.ui.core.mvc”

            xmlns=”sap.m”

              controllerName=”ctlv4.view.Tile” <———— This needs to match the app name

            xmlns:html=”http://www.w3.org/1999/xhtml“>

          AND

          sap.ui.controller(“ctlv4.view.Tile”, { … }); <————- same here

          Hope this helps someone else!

          Best regards

          Andre

          (0) 
  2. Tina Chen

    Hi , I have trouble add number in dynamic tile , I described in stackoverflow:

    sapui5 – How to set Number of Dynamic Tile in HCP portal service? – Stack Overflow

    I tried add destinations in “Configure Portal Service “:

    Name: northwind

    URL: http://services.odata.org/ http://services.odata.org/  http://services.odata.org

    Still returned:

    GET https://flpportal-iXXXXXXtrial.dispatcher.hanatrial.ondemand.com/sap/fiori/alert/destinations/northwind/Northwind/Northwind.svc/Employees/$count 404 (Not Found)

    (0) 
    1. Guy Roth

      Hi Tina,

      Destinations are a way for applications to access external services (e.g. OData). You cannot access data through destinations directly from the portal – only through an application that is deployed on your account.

      Please find more information here: SAP HANA Cloud Platform


      Guy Roth

      SAP HANA Cloud Platform, Portal Service

      If you find this answer useful or correct, please mark it accordingly for the benefit of other members.

      (0) 
      1. Tina Chen

        Thanks Roth,

        if I can’t use destinations in protal, how to set service url in dynanmic tile ? Just copy and paste the remote service URL? Why they always add  ‘/sap/fiori/(project name)‘ in front of URL which directed to 404 ?

        (0) 
        1. Guy Roth

          Hi Tina,

          Just to make clear, you CAN use destinations if they are managed by applications.

          For example, an application shows your open orders, and the application is using a destination to get the orders data from a backend system. You can then create a tile that shows the number of open orders (or any other data from that destination) by using the same URL that the application itself uses to get the data.

          Using the direct URL of the remote service might not work due to browser cross-origin security constraints. The usage of /sap/fiori/application-name is used exactly for this purpose – it tunnels requests to deployed applications through the base URL of the portal, making sure that requests are not blocked by cross-origin limitations.


          Guy Roth

          SAP HANA Cloud Platform, Portal Service

          If you find this answer useful or correct, please mark it accordingly for the benefit of other members.

          (0) 
    1. Ido Shemesh Post author

      Hi Silvia,

      The resources were automatically removed after the migration to the new blog platform. I am working on uploading them to our github repository and will update this blog once they are available.

      In the meantime lets try uploading the text here below..

      Regards, Ido

      Tile.view.xml

      <core:View xmlns:core=”sap.ui.core”
      xmlns:mvc=”sap.ui.core.mvc”
      xmlns=”sap.suite.ui.commons”
      controllerName=”employees.view.Tile”
      xmlns:html=”http://www.w3.org/1999/xhtml”>
      <html:style>
      .sapUiMedia-Std-Desktop .sapSuiteUiCommonsNwCCTxt.Auto>.sapMText, .sapUiMedia-Std-Tablet .sapSuiteUiCommonsNwCCTxt.Auto>.sapMText,
      .sapSuiteUiCommonsNwCCTxt.L>.sapMText, .sapSuiteUiCommonsNwCCTxt.M>.sapMText {
      font-size: 1.875rem;
      color: white;
      }

      .sapUiMedia-Std-Desktop .sapSuiteUiCommonsNwCSbh.Auto, .sapUiMedia-Std-Tablet .sapSuiteUiCommonsNwCSbh.Auto, .sapSuiteUiCommonsNwCSbh.L, .sapSuiteUiCommonsNwCSbh.M {
      font-size: 0.975rem;
      font-style: italic;
      color: #E3AE57 !important;
      }

      .tile{
      background-color: #232B2B;
      }

      .sapUiMedia-Std-Desktop .sapSuiteGTContent.Auto, .sapSuiteGTContent.L, .sapUiMedia-Std-Tablet .sapSuiteGTContent.Auto, .sapSuiteGTContent.M {
      height: initial !important;
      }

      .M .sapSuiteGTHdrTxt{
      padding-top: 5px;
      }

      .sapUiMedia-Std-Desktop .sapSuiteGTHdrTxt.Auto>.sapMText, .sapSuiteGTHdrTxt.L>.sapMText, .sapUiMedia-Std-Tablet .sapSuiteGTHdrTxt.Auto>.sapMText, .sapSuiteGTHdrTxt.M>.sapMText{
      color: white;
      }

      .sapSuiteTileCnt.News {
      background-color: inherit;
      }
      </html:style>
      <GenericTile
      id=”genericTile”
      class=”tile”
      size=”M”
      frameType=”TwoByOne”
      press=”onPress”>
      <tileContent>
      <TileContent footer=”Birthday: {path:’BirthDate’, formatter:’employees.util.Formatter.formatDate’}” size=”M”>
      <content>
      <NewsContent
      size=”L”
      contentText=”{TitleOfCourtesy} {FirstName} {LastName}”
      subheader=”{Title}”>
      </NewsContent>
      </content>
      </TileContent>
      </tileContent>
      </GenericTile>
      </core:View>

      Tile.controller.js

      jQuery.sap.require(“employees.util.Formatter”);

      sap.ui.controller(“employees.view.Tile”, {

      sURI: jQuery.sap.getModulePath(“employees”) +’/destinations/northwind/V3/Northwind/Northwind.svc/’,
      oModel: null,
      counter: 0,
      employeeArray: null,

      onAfterRendering: function() {

      var view = this.getView();
      var oViewData = view.getViewData();
      var genericTile = view.byId(view.createId(“genericTile”));
      if(oViewData !== undefined && oViewData.properties !== undefined ){
      var titleTextVar = oViewData.properties && oViewData.properties.titleText;
      genericTile.setHeader( titleTextVar )
      }
      else{
      genericTile.setHeader(“Get to know your colleagues…”)
      }

      this.oModel = new sap.ui.model.odata.ODataModel(this.sURI, true);
      var parameters = {};
      parameters.async = true;
      var that = this;
      parameters.error = function(){

      };

      parameters.success = function(oData, response){

      if(response.statusCode === 200){

      var controller = that;
      var view = controller.getView();
      controller.employeeArray = oData.results;
      var genericTile = view.byId(view.createId(“genericTile”));

      var jsonModel = new sap.ui.model.json.JSONModel();
      jsonModel.setData({modelData: oData.results});
      view.setModel(jsonModel);

      var empArr = controller.employeeArray;
      var internalCounter = controller.counter + 1;
      genericTile.bindElement(“/modelData/0”);

      setInterval(function(){

      debugger;
      if(internalCounter === empArr.length ){
      internalCounter = 0;
      }
      genericTile.bindElement(“/modelData/” + internalCounter);
      internalCounter+=1;
      },
      5000);

      }

      };
      this.oModel.read(“/Employees”, parameters);
      },

      onPress: function(){
      debugger;
      var oStaticTileView = this.getView(),
      oViewData = oStaticTileView.getViewData(),
      navTargetUrl = oViewData.properties && oViewData.properties.navigation_target_url;

      if (navTargetUrl) {
      if (navTargetUrl[0] === ‘#’){
      hasher.setHash(navTargetUrl);
      }
      else{
      window.open(navTargetUrl, ‘_blank’);
      }
      }
      }
      });

      Formatter.js

      jQuery.sap.declare(“employees.util.Formatter”);

      jQuery.sap.require(“sap.ui.core.format.DateFormat”);

      employees.util.Formatter = {

      formatDate: function (value) {
      if (value) {
      var oDateFormat = sap.ui.core.format.DateFormat.getDateTimeInstance({pattern: “MM.dd.yyyy”});
      return oDateFormat.format(new Date(value));
      } else {
      return value;
      }
      }
      };

      (2) 
  3. Daniel Spiess

    Thanks for this blog.

     

    Just for anybody else who might be struggling with the Service URL for the Dynamic Data / Dynamic Tile:

    This didn’t work for me: /sap/fiori/employees/destinations/northwind/V3/Northwind/Northwind.svc/Employees/$count

    Probably due to a newer version of WEB-IDE or something I don’t have a serviceUrl in my Components.js, so I couldn’t do the “proxifying” in part 1.

     

    But for me it also worked without this now.

    I entered /Northwind/V3/Northwind/Northwind.svc/Employees/$count  at Dynamic Data -> Service URL

    (where the first “Northwind” is the Destination name I have chosen in the HCP)
    Regards

     

    (0) 

Leave a Reply