Skip to Content
Author's profile photo Basar Ozgur Kahraman

Mobilize ALV Reports – Part 2 Create JQueryMobile Web Application with Datatables plugin

In my previous blog post we created a restful service that returns with ALV metada and data. Now we will develop a jquerymobile web client that calls this service and represents data in jquery datatables plugin.

Part 1 – Create RESTful service

Part 3 – Visualize ALV Data with Highcharts for iPad

Creating JqueryMobile Web Application

Pre-requisites:

  1. It is assumed that you are already familiar with HTML and the basic javascript usage
  2. Check over jquery ajax: http://api.jquery.com/jQuery.ajax
  3. Check over jquerymobile fundamentals & documentation: http://jquerymobile.com/demos/1.1.1/docs/about/intro.html
  4. Check over datatables usage: http://datatables.net

Steps:

  1. Create jquerymobile web page
  2. Call restful service to get alv data
  3. Parse alv metadata to create columns of datatables
  4. Initialize datatables plugin with alv data

index.html

<!DOCTYPE html>

<html>

    <!–<html manifest=”app.appcache”>–>

    <head>

    <title></title>

    <meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>   

    <meta name=”apple-mobile-web-app-capable” content=”yes”/>

    <meta name=”viewport” content=”width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no” />

    <link rel=”shortcut icon” href=”images/mysapreport.jpg” />

    <link rel=”stylesheet” href=”css/jqm/jquery.mobile-1.1.1.min.css” />

    <!– DataTables CSS     –>

    <link rel=”stylesheet” type=”text/css” href=”css/datatables/jquery.dataTables.css”/>  

    <link rel=”stylesheet” type=”text/css” href=”css/datatables/ColVisAlt.css”/>

    <script src=”js/jqm/jquery-1.7.2.min.js”></script>

    <script src=”js/jqm/jquery.mobile-1.1.1.min.js”></script>

    <!– DataTables –>

    <script type=”text/javascript” src=”js/datatables/jquery.dataTables.min.js”></script>              

    <script type=”text/javascript” src=”js/datatables/ColVis.min.js”></script>    

    <script type=”text/javascript” src=”js/datatables/TableTools.min.js”></script>    

    <script type=”text/javascript” src=”js/settings.js”></script>

    <script type=”text/javascript” src=”js/table.js”></script>

    <script>

        $.support.cors = true;

        jQuery.support.cors = true;                 

    </script>

</head>

<body>

<div data-role=”page” id=”alv” data-theme=”e”>

    <div data-role=”header” data-position=”fixed”>

        <h1>ALV</h1>

        <a href=”#settings”  data-role=”button” data-icon=”gear” data-theme=”b”>Settings</a>

    </div>

    <div data-role=”content” >

        <div data-role=”fieldcontain”>

            <label for=”transaction”>Transaction:</label>

            <input type=”text” name=”transaction” id=”transaction” value=”” />      

        </div>

        <div data-role=”fieldcontain”>

            <label for=”variant”>Variant:</label>

            <input type=”text” name=”variant” id=”variant” value=”” />

        </div>

        <a href=”javascript:getALV()”  data-role=”button” data-icon=”grid” data-theme=”b”>Call Report</a>      

        <br>

    </div>

</div>

<div data-role=”dialog” id=”settings”>

    <div data-role=”content” >

        <label for=”connectUrl”>Connect to:</label>

        <input type=”url” name=”connectUrl” id=”connectUrl” value=”” data-mini=”true” />

        <label for=”username”>Username:</label>

        <input type=”text” name=”username” id=”username” value=”” data-mini=”true” />

        <label for=”password”>Password:</label>

        <input type=”password” name=”password” id=”password” value=”” data-mini=”true” />

        <br>

        <a href=”javascript:exitSettings()” data-role=”button” data-icon=”delete”>Exit</a>

        <a href=”javascript:saveSettings()” data-role=”button” data-icon=”check” data-theme=”b”>Save</a>               

    </div>

</div>

<div data-role=”page” id=”showDatatable” data-theme=”e” data-add-back-btn=”true” data-dom-cache=”true”>

    <div data-role=”header” data-position=”fixed”>

        <h1 id=”datatableHeader”>ALV</h1>

        <div class=”ui-btn-right”>          

            <a href=”#chartRules” data-role=”button” data-icon=”star” data-theme=”e” data-back=”true”>Chart</a>          

        </div>

    </div>

    <div data-role=”content”>

        <div id=”dynamicDatatableDIV” >          

            <!–<table id=”dynamicDatatable” class=”tbl_basket_style”></table>–>

        </div>

    </div>

</div>

</body>

</html>

Call Restful Service:

function getALV(){

    alvData = [];

    alvMetadata = [];

    $.ajax({

        type: “GET”,             

        url: ‘http://‘ + $(“#username”).val() + ‘:’ + $(“#password”).val() + ‘@’ + $(“#connectUrl”).val() + ‘?tcode=’ + $(“#transaction”).val() + ‘&variant=’ + $(“#variant”).val(),

        data: “”,

        dataType: “jsonp”,

        contentType: “application/javascript”,

        username:$(“#username”).val(),

        password:$(“#password”).val(),       

        jsonpCallback:”jsonp_success”,

        crossDomain: true,

        cache: false,

        timeout: 10000,

        xhrFields: {

            withCredentials: true

        },

        beforeSend: function(xhr, settings){                                          

            $.mobile.showPageLoadingMsg();

        },

        complete: function(xhr, textStatus) {

            $.mobile.hidePageLoadingMsg();

            if (alvMetadata){

                createDynamicTable(getColumnData(alvMetadata),alvData);

                $.mobile.changePage(‘#showDatatable’);

                $(‘#datatableHeader’).text(reportDescription);              

            }

        },

        success: function(sys){      

        },

        error: function( result ){

            if (result.statusText !== “success”){

                alert(‘Error!! Unable to call ALV Report. Please check your settings & SAP connection’);

                $.mobile.changePage(‘#settings’);

            }

        }

    }); // Ajax posting  

}

function JSONP_SUCCESS(result){  

    reportDescription = result.description;

    alvMetadata = result.alvMetadata;             

    alvData = result.alvData;

    //sort ALV metadata according to col_pos

    alvMetadata.sort(function(a,b) {

        return (parseInt(a.col_pos) > parseInt(b.col_pos)) ? 1 : ((parseInt(b.col_pos) > parseInt(a.col_pos)) ? -1 : 0);

    } );

}

Datatables Columns Creation

function getColumnData(alvMetadata){

    var column = new Array();

    var type;

    var just;

    var sclass;

    var visible;     

    var visCount = 0;

    for(i=0;i<alvMetadata.length;i++){

        type = alvMetadata[i].inttype;

        just = alvMetadata[i].just;

        visible = alvMetadata[i].no_out;

        switch (type){

            case ‘D’:

                type = “date”;

                break;

            case ‘N’:

                type = “string”;

                break;      

            case ‘P’:

                type = “numeric”;

                break;

            case ‘I’:

                type = “numeric”;

                break;

            case ‘F’:

                type = “numeric”;              

                break;

            default:

                type = “string”;

                break;

        }

        switch (just){

            case ‘L’:

                sclass = “left-align”;

                break;

            case ‘R’:

                sclass = “right-align”;

                break;

            case ‘C’:

                sclass = “center-align”;

                break;

            default:

                sclass = “left-align”;

                break;

        }       

        if (visible == ‘X’ || visCount > 5)

            visible = false;

        else{

            visible = true;

            visCount++;

        }

        column.push({

            “mDataProp”:alvMetadata[i].fieldname.toLowerCase(),

            “sName”: alvMetadata[i].fieldname,

            “sTitle”: alvMetadata[i].seltext,

            “sType”: type,

            “sClass”: sclass,

            “bVisible”: visible              

        });

    }

    return column;

}

Initialize Datatables

function createDynamicTable(aColumnData,aDataSet){     

    $(‘#dynamicDatatableDIV’).html( ‘<table id=”dynamicDatatable” class=”tbl_basket_style”></table>’ );             

    var alvTable = $(‘#dynamicDatatable’).dataTable( {

        “sDom”: ‘rfCtip’,     

        “bStateSave”: true,//length, filtering, pagination and sorting not change when refresh(cooki)

        “sPaginationType”: “full_numbers”,                      

        “iDisplayLength”: 65536,      

        “oColVis”: {          

            “bRestore”: true                      

        },        

        “bUseRendered”: false,

        “aaData”: aDataSet,      

        “aoColumns”: aColumnData

    } );  

}

Test

After publishing service on your own system, you can call it only by editing settings in MySapReport . Web client saves your settings on localstorage except password. Password is saved on sessionstorage. So don’t need to edit connection url and username in each visit of client application but password is asked for each session.

You can run demo with empty settings.

If you want, you can publish client as BSP pages on sap ITS. For step by step instructions read John Moy’s blog .

You can find all sources codes on https://github.com/basarozgur/MySapReport

Screen Shots:

   Transaction code entry

/wp-content/uploads/2012/09/m1_140952.jpg

   Settings

/wp-content/uploads/2012/09/ms_141014.jpg

 

   Report Data

/wp-content/uploads/2012/09/dt_141015.jpg

  

   Datatables Show / Hide Columns

/wp-content/uploads/2012/09/sh_141016.jpg

Assigned Tags

      5 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Syambabu Allu
      Syambabu Allu

      Hi,

      Nice work Basar.

      Cheers,

      Syam.

      Author's profile photo Steve Oldner
      Steve Oldner

      Amazing! Wow!  Just been learning and using BSP + jQueryMobile for a payroll app (John Moy inspired) and launchpad BUT I still have a tremendous amount of background to learn.

      Did I see correctly that you used Python?

      Author's profile photo Basar Ozgur Kahraman
      Basar Ozgur Kahraman
      Blog Post Author

      Hi Steve,

      Only jquery and compatible plugins are used. Html+Css+Javascript enough for client side.

      If you check whole blog series, you will find all sources that you need. please feel free to ask questions at any point..

      Author's profile photo Steve Oldner
      Steve Oldner

      It was over in your Github account where I saw the , main.py.

      I do have a question about using the cache manifest with BSP. Specifically about linking to the jquery, jqueryui and jquerymobile links.  How do I use/code that in a BSP?  Currently I am  linking stylesheet to http://code.jquery...css and the scripts to http://code.jquery....min.js and mobile.js.  From what I have read, I can copy these to the MIME and use them from there.  But haven't found example code on how to use mime at a public level.

      Since our project is primarily focused on mobile html5, having the jquery coding in cache would simply and speed it up.

       

      Could you point me somewhere? Or indicate what I missed?

      Thanks!

      Author's profile photo Basar Ozgur Kahraman
      Basar Ozgur Kahraman
      Blog Post Author

      Hi,

      There is a main.py file because i use google app engine to host my application and app engine only let you host java, phyton or go projects.

      I prefer to use CDN hosting for jquery files. You can find more info on http://jquerymobile.com/download/.

      Also there is a clear explanation on John Moy 's blog about using libraries in MIME