Skip to Content

Introduction

In this post we will build an application containing an input field with a Value Help dialog. For that, we will implement a Gateway Query Service that returns the requested list of values. Then we will implement a dialog window with a table in it. With a line selection, we will implement an event which closes the dialog and transmits the selected value to the original input field.

Installed components

We used SAP UI5 v1.12, NetWeaver Gateway 2.0 SP6 and the current version of the Chrome Browser.

Gateway Service Implementation

As of NetWeaver Gateway 2.0 SP4 it is recommended to use the Gateway Service Builder to model the Gateway service Entity Data Model (EDM) [1]. The SEGW is the transaction for that. There we create a new project ZMATNR_VALUE_HELP for the value help service.

/wp-content/uploads/2013/06/image002_236394.jpg

We will need one entity MaterialCode for our Value Help Service which contains three properties: material number, material type and description.

For that, we create the Entity MaterialCode along with the related EntitySet MaterialCodeSet:

/wp-content/uploads/2013/06/image004_236393.jpg

Next, we select the created entity and define the properties Matnr, Mattype and Descr:

We define the Matnr property as the key property.

/wp-content/uploads/2013/06/image006_236395.jpg

All properties have defined EDM type, max length, label, ABAP field and ABAP type.

We define the ABAP Type as a Data element, MATNR, MTART, and MAKTX respectively.

/wp-content/uploads/2013/06/image008_236402.jpg

The model is finished now, and we can generate the runtime objects – use icon /wp-content/uploads/2013/06/image010_236404.jpg in the menu bar. 

We keep the proposed names and generate the ABAP classes.

Check if the generation log is green.

/wp-content/uploads/2013/06/image012_236403.jpg

Now we select the data provider class (ending with _DPC_EXT):

/wp-content/uploads/2013/06/image014_236408.jpg

When double-click on the name we switch to the class builder. We need to redefine the method MATERIALCODESET_GET_ENTITYSET there.

For simplicity, we put the SELECT statement fetching the data directly from MARA/MAKT tables. In the real life, you would usually call a BAPI or any other business function here fetching the values and mapping them to the service entity (represented by the exporting parameter et_entityset).

METHOD materialcodeset_get_entityset.
    SELECT m~matnr m~mtart t~maktx
       INTO CORRESPONDING FIELDS OF TABLE et_entityset
       FROM ( mara AS m
         LEFT OUTER JOIN makt AS t ON m~matnr = t~matnr )
         UP TO 30 ROWS.
ENDMETHOD.

Now we can leave the class and the service builder and go to the Gateway hub (which is in our case the same system). On the Gateway hub we publish the service into the service catalog. For that, we use the transaction /IWFND/MAINT_SERVICE and open up the dialog to add a new service, then provide a system alias for the backend system (for local services we use the alias LOCAL).

/wp-content/uploads/2013/06/image016_236409.jpg

We keep all values default and get the service published as follows:

/wp-content/uploads/2013/06/image018_236410.jpg

Note: (1) ODATA ICF node must be green, and (2) the System Alias must contain a system alias pointing to the backend system where we created the model and data provider.

Now the service is ready to use and we can test it in the Gateway Client (check the button within the ICF Nodes area).

We change the URL to /sap/opu/odata/sap/ZMATNR_VALUE_HELP_SRV/MaterialCodeSet?$format=json

Then execute the service and check its output.

In our case we’ve got the following JSON document.

/wp-content/uploads/2013/06/image020_236411.jpg

In our SAP UI5 application we will use this service for fetching the Material codes and descriptions. 

Note, that we have requested the output in the JSON format ($format=json) as this format is directly supported by JavaScript and SAP UI5.

SAP UI5 Application

Our SAP UI5 project’s name in Eclipse is ValueHelp. It contains an initial Javascript view “main”. This is how our project structure looks like:

/wp-content/uploads/2013/06/image022_236412.jpg

As we are going to use the UI5 controls ToolPopup and Table, we need to load the relevant UI5 libraries. For that, we need to include them in the so-called bootstrap declaration. We open the index.html and extend the script parameter data-sap-ui-libs with two more libraries sap.ui.table and sap.ui.ux3.

<script src="resources/sap-ui-core.js"
             id="sap-ui-bootstrap"
             data-sap-ui-libs="sap.ui.commons,sap.ui.table,sap.ui.ux3"
             data-sap-ui-theme="sap_goldreflection" >
</script>

As the next step we update the main.view.js file and implement the function createContent().  We will implement the input field with the UI5 control sap.ui.commons.ValueHelpField and display a field label with another UI5 control sap.ui.commons.Label

We also use some layout controls Panel and LayoutMatrix to make the application appearance nicer.   

  createContent : function(oController) {

      var oPanel = new sap.ui.commons.Panel({
              text : "Select Material Number"
      });

      var oLayoutMatrix = new sap.ui.commons.layout.MatrixLayout({
                          width : "60%",                         // control width relative to window
                          widths : [ "30%", "40%", "30%" ]  // widths of the columns
      });

      var oMatnrLabel = new sap.ui.commons.Label("idMatnrLabel",
              {text: "Material Number"});

      // Input Field for Material Number with Value Help
      var oMatnrInput = new sap.ui.commons.ValueHelpField("idMatnrInput", {
            valueHelpRequest: function(oEvent){
            }          
      });
    
      oLayoutMatrix.createRow(oMatnrLabel, oMatnrInput);
      oPanel.addContent(oLayoutMatrix);
      return oPanel;
  }

The output in Chrome looks now as follows.      

/wp-content/uploads/2013/06/image024_236413.jpg

The control ValueHelpField has an event valueHelpRequest which we implement as a dialog window provided by the UI5 control ToolPopup

valueHelpRequest: function(oEvent){
    var oValueHelpDialog = new sap.ui.ux3.ToolPopup({
                        modal: true,
                        inverted: false,                          // disable color inversion
                        title: "Select Material Number",
                        opener:  "idMatnrInput",             // locate dialog next to this field
                        closed: function (oEvent) {
                    }
          });
}

Note: the control event closed is not yet implemented; we will do it later to extract the selected value from the table which will be placed in the dialog window.    

Now we add a button “OK” to the Dialog window which is used to close the dialog window. This code is placed directly after the declaration of oValueHelpDialog

var oOkButton = new sap.ui.commons.Button({
                        text: "OK",
                        press: function (oEvent) {
                                   oEvent.getSource().getParent().close();
                        }
            });
           
oValueHelpDialog.addButton(oOkButton);

oValueHelpDialog.open();

Now the Value Help dialog window can be opened and closed.     

/wp-content/uploads/2013/06/image026_236417.jpg

As the next step we place the table with two columns Matnr and Descr into the dialog window. We insert this code after the addButton(oOKButton). 

Note: the fields Matnr and Descr must refer to our underlying data model (e.g. provided by the Gateway Service or locally).   

  var oHelpTable = new sap.ui.table.Table({
        selectionMode: sap.ui.table.SelectionMode.Single,
        visibleRowCount: 7,
        width: "300pt"
  });

  oHelpTable.addColumn(
        new sap.ui.table.Column({
                label: new sap.ui.commons.Label({text: "Material Number"}),
                template: new sap.ui.commons.TextView().bindProperty("text", "Matnr"),
                sortProperty: "Matnr",
                filterProperty: "Matnr",
        })
  );

  oHelpTable.addColumn(
        new sap.ui.table.Column({
                label: new sap.ui.commons.Label({text: "Description"}),
                template: new sap.ui.commons.TextView().bindProperty("text", "Descr"),
                sortProperty: "Descr",
                filterProperty: "Descr",
        })
  );

  oValueHelpDialog.addContent(oHelpTable);

Now we can see the dialog window with the empty table:  

/wp-content/uploads/2013/06/image028_236418.jpg

In the next step we fetch the data either from a Gateway service or define it locally as a JSON array.

We use the global variable DATABINDING to switch between these two modes – we use true for the Gateway service call and false for the local data binding. 

Insert this line into your main.controller.js function onInit() 

/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time
* initialization.
*/
   onInit: function() {
        DATABINDING = false;
   },

Now we continue with the main.view.js and insert before the addContent() line the following code:  

  var oHelpModel = new sap.ui.model.json.JSONModel();
  if (DATABINDING) {
    console.log("Gateway Databinding for Value Help");
// http:///sap/opu/odata/sap//MaterialSet?$select=Matnr,Descr&$format=json
      var helpURL = "http:///sap/opu/odata/sap//MaterialSet";
      var queryString =”$select=Matnr,Descr&$format=json”;
      oHelpModel.loadData( helpURL, queryString, false);
  }
  else {
      console.log("Local Databinding for Value Help");
      oHelpData =
          {"d":{"results":[
                        {"Matnr":"4711","Descr":"Snowboard"},
                        {"Matnr":"4712","Descr":"Mountain Ski"},
                        {"Matnr":"4713","Descr":"Backcountry Ski"},
                        {"Matnr":"4714","Descr":"Freeride Ski"},
                        {"Matnr":"2011001","Descr":"Ski Boots"},
                        {"Matnr":"2011002","Descr":"Ski Poles"},
                        {"Matnr":"2011003","Descr":"Rucksack"},
                        {"Matnr":"5550001","Descr":"Ski Googles"},
                        {"Matnr":"5550002","Descr":"Ski Helmet"},
                        {"Matnr":"5550007","Descr":"GPS Unit"}
      ]}};
      oHelpModel.setData(oHelpData);
  }
           
  oHelpTable.setModel(oHelpModel);
  oHelpTable.bindAggregation("rows", "/d/results");

The structure of the local JSON object is aligned with the Odata Entity Model Structure, so that the same data binding can be used here for local and Gateway data binding.    

Now the dialog window shows up our test data:  

/wp-content/uploads/2013/06/image030_236419.jpg

However, the selection is not yet transferred back to the input field. 

For that, we implement the event closed of the ToolPopup control which we already defined but left empty.    

  closed: function (oEvent) {
      // return selected tabled line/value
      var oCore = sap.ui.getCore();
      var oMatnrInput = oCore.byId("idMatnrInput");
      var oContext = oHelpTable.getContextByIndex(oHelpTable.getSelectedIndex());
      if (oContext) {
            var oSel = oContext.getModel().getProperty(oContext.getPath());
            oMatnrInput.setValue(oSel["Matnr"]);
      };
  }

The value of the selected row can be showed now in the input field:

/wp-content/uploads/2013/06/image032_236420.jpg    

Postscriptum

All code samples can be tested within an Eclipse project. Run it in Eclipse as a Web application (we used the Jetty http server plugin for that) and copy the URL into the Chrome Browser. Keep the Jetty window open, and refresh your browser window (F5) to re-run the application. To see the console output, use F12 in the browser to switch to the debugging mode.

References

[1] Entity Data Model (EDM) – http://www.odata.org/documentation/overview#41_Entity_Data_Model_EDM_Overview 

[2] UI5 Blog – Javascript Crash Course for ABAP Developers  http://scn.sap.com/blogs/ui5-for-abap/2013/05/02/javascript-crash-course-for-abap-developers 

About the authors

Vladislav Bezrukov is Development Architect at SAP Consulting focusing on integration technologies, Web and REST Services in ABAP NetWeaver platform (ABAP WS, Gateway). His further professional interests extend to SAP UI5 and HANA technologies, which he is using in his projects in the past couple of years. Email: vladislav.bezrukov@sap.com 

Florian Backfisch is Development Consultant at SAP Consulting. His professional interests are ABAP and UI technologies. Email: florian.backfisch@sap.com 

Johannes Demund is Development Consultant at SAP Consulting. He focuses on ABAP technologies and user interfaces, including NetWeaver Business Client, WebDynpro ABAP, and SAP UI5. Email: johannes.demund@sap.com

Disclaimer

This blog does not represent nor substitute the official SAP documentation. The views expressed by the authors do not necessarily reflect the views of their employer.

To report this post you need to login first.

14 Comments

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

  1. Sathish Kumar

    Hi Vladislav,

    I implemented this Valuehelp in one of our UI5 application. The Valuehelpfield is towards the right of the screen. When the value help opens, it is now opening outside the screen and a horizontal scroll bar appears which looks pretty awkward. Did you run into any situation like this? Also, I couldnt give any setting in the ToolPopup api or ValueHelpfield api so that the popup opens below the control instead of right side of the control. If you have any inputs, that would be great.

    Sathish.

    (0) 
    1. Vladislav Bezrukov Post author

      Hi Sathish,

      for the problem with window placement, you can control it by the property “opener” on the ToolPopup control; see control help for further details.

      Check the UI5 version; I am aware of some problems with the versions 1.10 and below. 1.12 and higher should be fine.

      (0) 
      1. Sathish Kumar

        Hi Vladislav,

        Thanks, I implemented with the opener. I found some help from UI5 SDK. I have another question. I tried to implement the above example. In my F4 help, I have to add some search fields and based on the search critieria, I want to retrieve the results.

         

        I used the following code:

        var material=sap.ui.getCore().getControl(“material”).getValue();

        var desc = sap.ui.getCore().getControl(“desc”).getValue();

        var url = ‘/MATERIALSet?$filter=substringof(‘+”‘”+material+”‘”+’,ExtProdID) and substringof(‘+”‘”+desc+”‘”+’,ProductDesc)’;

        var oModel = sap.ui.getCore().getModel();

        oModel.read(url, null, null, true, function(oData, oResponse){

                   sap.ui.getCore().byId(“HT1”).setModel();

                    var sort1 = new sap.ui.model.Sorter(“ExtProdID”);

                    sap.ui.getCore().byId(“HT1”).bindRows(url,null);

                                }, function(){

                                       alert(“Data not found”);});

         

        I get two problems in the above code:

        1. bindRows(url, null) returns an error. My oData service is fired correctly and the values are retrieved but at the time it is binding, somehow $count is added at the end of the actual url. Since there are filter parameters already, this syntax is not correct. So I get error in the console log.

        2. ABAP Gateway is called two times. Once during oModel.read and the second during bindRows.

         

        I tried /../sap/opu/odata/sap/ZPRODUCTS_SRV/MATERIALSet?$filter=substringof(‘A1’,ExtProdID)$select=ExtProdID&$format=json

        I got this error message: In the context of Data Services an unknown internal server error occured.

        If I dont use the filter, it is working fine.

        Do you have any suggestion on how to do filter parameters?

        (0) 
  2. Rufat Gadirov

    Hi Vladislav ,


    thank you so much for this great tutorial!!


    Currently, I want to implement multiple value help dialogs.

    What do you recommend? Using only one definition of the control/method or using multiple controls /methods for each value input field?


    Is there a good possibility to achieve that dynamically?


    Best regards,

    Rufat

    (0) 
  3. guest 201232

    Is there a way to add an invisible column or set a Key for the Value so instead of getValue i could get getSelectedKey or smth. Because i have a model which consists of a ValueId and ValueText. I want to display the ValueText, but when I want to write to database i need to get the ValueId which corresponds to the ValueText. How can I do that without creating a separate column for it?

    (0) 
  4. rohan poludasu

    Nice Post,

    But when implementing iti am getting an error that the databinding is not defined can someone please help me with this. I am new to sapui5.

    Thanks and regards,
    Rohan

    (0) 

Leave a Reply