Skip to Content
Technical Articles

Creating an SAP Mobile Card really quickly

In this blog post I’m going to show you how I created a mobile card app very easily with SAP Cloud Platform Mobile Services. I recommend using this functionality when you want to release to the user simple information on mobile devices with very little time. You can even make use of push or add actions to be triggered by the user, but I’m not going to show that here.

 

Use Case

In this example we are going to imagine the case where we need to build a card to show the information that is shown in a tile of an SAP Fiori Overview Page. This is the Account Receivable Overview Fiori App. Let’s say we want to develop a mobile card with the information that we see in the Days Sales Outstanding card, marked in red on the right-hand side.

The first thing we need to do is to set up the destination to the backend system. We do that in the Features tab, inside the Connectivity feature.

I created a destination called UXM_CAL and we can test it’s working fine right from there. There is a button to send a ping and you can also explore the entities.

 

Create the SAP Mobile Card

Now we can create the mobile card and I choose a template from the ones available. I selected one called Mobile Service User Registration by Time just because I want to make use of the chart.

In the Info tab I give it a name and select the destination I created before.

Moving to the URLs tab I add my two urls that I’ve got from the DSO tile. I pasted them exactly as are being used in the Overview Page, with the same parameters. You can get the data and check that you see the correct result. You can notice there is a place to configure the parameters for the url but this way is working the same.

In the Editor tab I changed the code to adapt it to my use case. There is one HTML code for the front of the mobile card and another one for the back, plus a CSS for styling.

From the code of the front of the card I changed the title, description and the part that fills the chart with the data coming from the oData service. Now it looks like this:

<div id="mySimpleTemplate" data-type="text/x-handlebars-template">
   <div class="charts-card-template">
      <div class="header" style="padding-left: 16px">
         <div  style="height: 30px text-align: left;">
               <span style="font-weight: bold; font-size: 24px; float: left; display: inline; padding-top: 16px">
                     Days Sales Outstanding
                </span>
         </div>
         <div style="text-align: left;">
               <span style=" font-size: 14px; clear: left; float: left;  display: inline; padding-top: 4px">
                     by month, one year
                </span>
        </div>
      </div>
      <div id="user-registrations-chart" style="padding-top: 100px">
      </div>
      <script type="text/javascript">
         var oData = sap.deck.renderers.context.currentlyRendering.renderer.model.oData;
         //var statistics = oData.Statistics;
         var statistics = oData.dataSets[0].data.d.results;
         var data = [];

//  Removed code from the template
/*          for (var i = 0; i < statistics.length; i++) {
             for (var j = 0; j < statistics[i].connectionList.length; j++) {
                 if (data.find(function(elem) {
                         return elem.key === statistics[i].connectionList[j].key;
                     })) {
                     data[j].value += statistics[i].connectionList[j].value;
                 } else {
                     data.push({
                         key: statistics[i].connectionList[j].key,
                         value: statistics[i].connectionList[j].value
                     });
                 }
             } */
//  End of removed code             

//  Inserted new code             
          for (var i = 0; i < statistics.length; i++) {
                     data.push({
                         key: statistics[i].CalendarMonthName,
                         value: statistics[i].DaysSalesOutstanding
                     });
             }         

         var arrayOfZeroValues = data.filter(function(item) {
             return item.value === 0;
         });
//  End of inserted code         

         if (arrayOfZeroValues.length === data.length) {
             var chart = document.getElementById("user-registrations-chart");
             chart.style.fontSize = "20px";
             chart.style.textAlign = "center";
             chart.innerHTML = "No Data";
         } else {
             var margin = {
                     top: 20,
                     right: 20,
                     bottom: 70,
                     left: 65
                 },
                 width = 330 - margin.left - margin.right,
                 height = 350 - margin.top - margin.bottom;
             var values = data.map(function(d) {
                 return d.value;
             });
             var keys = data.map(function(d) {
                 return d.key;
             });
             var x = d3.scale.ordinal().rangeRoundBands([0, width], .1).domain(keys);
             var y = d3.scale.linear().range([height, 0]).domain([0, d3.max(values)]);
             var xAxis = d3.svg.axis().scale(x).orient("bottom");
             var yAxis = d3.svg.axis().scale(y).orient("left");
             var svg = d3.select("#user-registrations-chart").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
             svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")").call(xAxis).append("text").attr("dy", "+4em").attr("dx", "+8.5em").style("text-anchor", "middle").text("Months").style("font-size", "15px").style("font-weight", "bold");
             svg.append("g").attr("class", "y axis").call(yAxis).append("text").attr("transform", "translate(-20,40) rotate(-90)").attr("y", 0).attr("dy", "-2.3em").attr("dx", "-2.5em").style("text-anchor", "end").text("Days").style("font-size", "15px").style("font-weight", "bold");
             var bars = svg.selectAll("rect").data(data).enter().append("rect").attr("x", function(d) {
                 return x(d.key) + 5;
             }).attr("y", function(d) {
                 return y(d.value);
             }).attr("width", function(d) {
                 return x.rangeBand() - 10;
             }).attr("height", function(d) {
                 return height - y(d.value) - 0.5;
             }).style("fill", "#B1E0FD");
         }

         svg.selectAll('g.x.axis g text').each(function (d) {
         var el = d3.select(this);
         var splitText= d.split('/').reverse();
         el.text('');

         for (var i = 0; i < splitText.length; i++) {
         var tspan = el.append('tspan').text(splitText[i]);
         if (i > 0) {
            tspan.attr('x', 0).attr('dy', '15');
         }
         }
         });
      </script>
   </div>
</div>

Switching to the back of the card, I want to display what is shown in the header of the DSO tile. I replaced the HTML code with this one:

<div id="mySimpleTemplate" data-type="text/x-handlebars-template">
   <div class="charts-card-template">
      <div >
            <span style="font-weight: bold; font-size: 24px; float: left; display: inline; padding:16px">
               Days Sales Outstanding
            </span>
      </div>
      <div style="clear:both;">
      </div>
      <hr>
      <div>
      <span style="float:left;margin-left:16px;margin-top:10px;padding-bottom:10px">
      This card shows the total days sales outstanding by month for the last 12 months
      </span>
      </div>
            <div style="clear:both;">
      </div>
      <hr>

      <div >
         <span id="dso-kpi" style="float:left;margin-left:16px;margin-top:10px;">
         </span>
      </div>
      <div style="clear:both;">
      </div>

      <div >
         <span id="dso-unit" style="float:left;margin-left:16px;margin-top:0px;">
         Average DSO
         </span>
      </div>
      <script type="text/javascript">
         var oData = sap.deck.renderers.context.currentlyRendering.renderer.model.oData;
         var dsokpi = document.getElementById("dso-kpi");  
         var dsokpivalue = document.createElement('span');
         dsokpivalue.innerHTML = oData.dataSets[1].data.d.results[0].DaysSalesOutstanding; 
         dsokpi.appendChild(dsokpivalue);
      </script>
   </div>
</div>

I did a few changes in the CSS to make the labels of the chart readable and use another font for the back of the card.

html, body{
    height: 100vh;
    font-family: Helvetica;
    }
    
    .charts-card-template{
    background: linear-gradient(to bottom right,#589CCE,#226596);
    color: #FFF;
    width: 100%;
    height: 100vh;
    display: block;
    margin: auto;
    }
    
    .header {
    background-color: solid #CEDDEC;
    height: 40px;
    padding-left: 16px;
    border-bottom: 0,5px solid #CEDDEC;
    }
    
    hr{
    margin: 0;
    }
    
    #card-info{
    font-size: 15px;
    padding: 10px 15px;
    }
    
    #no-data{
    font-size: 20px;
    text-align:center;
    }
    
    svg{
    display: block;
    margin: auto;
    }
    
    .axis text {
    font-size:12px;
    stroke: #CEDDEC;
    fill: #fff;
    shape-rendering: crispEdges;
    stroke-width: 0;
    }
    
    .axis path, .axis line {
    fill: none;
    stroke: #CEDDEC;
    shape-rendering: crispEdges;
    }
    
    .x.axis .tick text {
    transform: rotate(-45deg) translate(-18px,5px);
    }
    
    /* new entries */
    #dso-kpi{
    font-family:72,72full,Arial,Helvetica,sans-serif;
    font-weight: 400;
    font-size: 40px;
    background-color: none;
    }
    
    #dso-unit{
    font-weight: 400;
    font-size: 12px;
    background-color: none;
    }

At this point you can see a preview of how is going to look like. The last step is to publish the mobile card version to make it productive.

 

End Result

Users can use the QR code from their mobile devices to subscribe to the new mobile card. The end result looks like this:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Conclusion

I wish this may have helped you develop a new skill, solve and issue or that you bookmarked it for future use. I’m confident you will find it very easy. Some of you may fill more confortable with your preferred technology, but there is always room for a new tool in your toolbox, and besides, you can achieve this with just a little bit of HTML.

 

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