Mobile Menu

FIORI APP Enhancement: Suggestions Functionality for Input Field

In my JS development I once encountered a very interesting case, when it was necessary to enhance FIORI APP.

On the outside it seems easy to reach the input field by the suggestion list. It is like a Google request: you enter some words and the input field provides you with suggested variants to complete your question.

Firs of all, let us have a look at the input field which should be enhanced in the fragment.xml file. So, the field can be defined like this:

  <Input maxLength=”30″

                       id=”ProductInput”

                       tooltip=”{i18n>PRODUCT}”

                       change=” handleProductInputChange”

                       editable=”{path : ‘ProductInput_FC’, formatter:’myFioriAPP.util.getEditable’}”

                       visible=”{path : ‘ ProductInput_FC’, formatter: myFioriAPP.util.getVisibility’}”

                       placeholder=””

                       value=”{ProductDescription}”

/>

Obviously, suggestion aggregation is not included by the design in this field.

The documents from FIORI APPs library () provide us with the information about enhancement points defined by SAP UI5 developers.

From a UI-development point of view, the Extension points are divided into the following types:

  1. Extension points in views;
  2. UI controller extensions;

So, the first plan for development was like the following one:

  1. Hide a Productinput filed using the UI controller extension point;
  2. In the XML-extension point add a new input filed with all necessary properties and aggregations.
  3. To develop a new handler for changing a new Input field with suggestion items;

This plan was implemented.

Create a new ext.controller.js and put the next code to hide the field:

extHookOnDataReceived: function(oHeaderContext) {

                    //…

                    //Set Visible parameter to false value in order to hede ProductInput field

                    this.byFragmentId(‘ProductInput’).setVisible(false);

                    //…

}

The next XML-fragment contains a new UI Input field. This code should be placed in the ext.fragment.xml file

<core:FragmentDefinition xmlns:m=”sap.m” xmlns:core=”sap.ui.core” xmlns:layout=”sap.ui.layout”>

<Input xmlns=”sap.m”

                           id=”ZProductInput”

                           value=”{ProductDescription}”

                           editable=”{path : ‘ZProduct_FC’, formatter:MyFioriAPP.util.getEditable’}”

                           visible=”{path : ‘ZProduct_FC’, formatter:’MyFioriAPP.util.getVisibility’}”

                           type=”Text”

                           showSuggestion=”true”

                           suggest=”onProductTyped”

                           suggestionItems=”{json>/results}”

                           suggestionItemSelected=”onProductSelected”

                            >

                        <suggestionItems>

                           <core:Item text=”{json>Products}” />

                        </suggestionItems>

                    </Input>

</core:FragmentDefinition>

To handle a new UI input field, we should create a new controller.js with the next fragment of the code:

 onAddressTyped: function(oEvent) {

                    //get the entered text from input field

                    var sTerm = oEvent.getParameter(“suggestValue”);

                    var self = oEvent.getSource();

                    if (sTerm) {

                                        var oModel = this.oApplicationFacade.getODataModel();

                                        oModel.read(“/<nameOfSet>?search=” + sTerm, oEntry, {

                                                            success: function(data) {

                                                                                //set model json to the Input UI element

                                                                                self.setModel(oModel, “json”);

                                                                                //set retrieved from oData service data to the json model of Input UI elevent

                                                                                self.getModel(“json”).setData(data.d);

                                                                                //set filter on the displayed suggestion items collection                                                                                                                                           

                                                                                self.setFilterFunction(function(sTerm, oItem) {

                                                                                                    return oItem.getText().match(new RegExp(“sTerm”, “i”));

                                                                                });

                                                            },

                                                            error: function(oError) {

                                                                                console.log(oError);

                                                            }

                                        });

                    }

}

As a result, the new field with suggestion items will be visible in the UI. Funny but true: end-users find the Product input field at the bottom of the screen. Why? Because the XML-extension point is only at the bottom of the screen in the FIORI APP. They were confused and asked to return the Product input field in its own place. I realized that the described way of enhancement does not fit my case. After some time the solution was found.

I found out that the most powerful capabilities were in the UI control extensions, I mean the extHookOnDataReceived  extension point. This point can be named differently in different FIORI APPS. You can find the exact name in the Extensibility Documentation of a particular FIORI APP. Find the points which are between the data and binding the data to view. In that kind of points, you can act with the data before binding and you have a possibility to make changes in the view before binding.

In my case extHookOnDataReceived gave me a possibility to change properties of the Product input field using JS.

And the development plan turned into the next one:

  1. Activate suggestion property;
  2. Define the Item for suggestion purpose;
  3. Bind suggestionItems aggregation;
  4. Attach the event handler to the suggest event of the input field.

This plan was good but not flawless. The main challenge was to make a call to the OData service. In the attachSuggest  body of the event handler the ApplicationFacade level is not visible. You do not have an OData model on the level of APP. In means that you cannot use the read function. It would be a problem if we did not have an ajax call. So, the solution was found.

All the code below should be written in the UI extension:

 extHookOnDataReceived: function(oHeaderContext) {

                    // In order to activate suggestion fist of all we have to turn on ShowSuggetsin parameter

                    this.byFragmentId(“ProductInput “).setShowSuggestion(true);

                    //Define Item variable which will be used as Suggestion Items. The text parameter binds to Products path of json model;

                    var item = new sap.ui.core.Item({

                                        text: “{json>Products}”

                    });

                    //Also we have to define aggregation suggestionItems and bind the results of responding from Odata service

                    this.byFragmentId(“ProductInput “).bindAggregation(“suggestionItems”, “json>/results”, item);

                    //currently all preparation is done. Then we use attachSuggest function in order to attach and define function which will be executed every time you type any symbols in the input field.

                    this.byFragmentId(“ProductInput “).attachSuggest(function(oEvent) {

                                        //get the entered text from input field

                                        var sTerm = oEvent.getParameter(“suggestValue”);

                                        var self = oEvent.getSource();

                                        if (sTerm) {

                                                            // URL to oData service                 

                                                            var url = “/sap/opu/odata/sap/<NemaOfService>/<nameOfSet>?search=” + sTerm;

                                                            var oModel = new sap.ui.model.json.JSONModel();

                                                            //as we don’t have access to the Model on the ApplicationFasade level, we can use ajax call

                                                            $.ajax({

                                                                                url: url,

                                                                                jsonpCallback: ‘getJSON’,

                                                                                contentType: “application/json”,

                                                                                dataType: ‘json’,

                                                                                success: function(data) {

                                                                                                    //set model json to the Input UI element

                                                                                                    self.setModel(oModel, “json”);

                                                                                                    //set retrieved from oData service data to the json model of Input UI elevent

                                                                                                    self.getModel(“json”).setData(data.d);

                                                                                                    //set filter on the displayed suggestion items collection                                                                                                                                           

                                                                                                    self.setFilterFunction(function(sTerm, oItem) {

                                                                                                                        return oItem.getText().match(new RegExp(“sTerm”, “i”));

                                                                                                    });

                                                                                }

                                                            });

                                        }

                    });

},

Thus, your Input field will be enriched with suggestion items collection. It improves the usability of the input field and increases the convenience of SAP UI5 application in general, because now there is no need to use the Selection dialog for searching. Your input field looks like Google.

FIORI_Product_Suggestion_01
Pic. 01 Fiori :: Product Suggestion Sample