Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[Fiori Elements] Custom Column in a Table is not visible

I had a generated Fiori Elements App (done by using @sap/generator-fiori), containing a List, where I needed to add a custom column containing a Button. I found this well explained in the official documentation:

https://sapui5.hana.ondemand.com/#/topic/d525522c1bf54672ae4e02d66b38e60c

I followed the instructions exactly, but it didn’t work. When comparing my manifest.json again with the example, I noticed one minor difference. In my generated App, there was an extra items/ in front of the @com.sap.vocabularies.UI.v1.LineItem.

My generated App
The manifest.json sample

After removing items/ the custom column was suddenly visible. When I noticed the difference, I thought that would never be the reason. Luckily, I tested it after all. That really is a big problem with Fiori Elements. These are problems that can no longer be solved by debugging or similar.

Here some more helpful links, when challenging with a custom column:

https://github.com/SAP-samples/fiori-elements-feature-showcase/blob/main/README.md#add-custom-column-extensibility

https://ui5.sap.com/test-resources/sap/fe/core/fpmExplorer/index.html#/customElements/customColumnContent

[SAPUI5] Place fields horizontally opposite each other

Because I always forget how to place a field at the beginning of a line and one opposite at the end, I create this post…

The easiest way to do this is using a Flex Box and the property justifyContent like in this sample: https://sapui5.hana.ondemand.com/#/entity/sap.m.FlexBox/sample/sap.m.sample.FlexBoxOpposingAlignment

<FlexBox alignItems="Center" width="100%" justifyContent="SpaceBetween">
    <Text text="Text1" textAlign="Begin"/>
    <Text text="Text2" textAlign="End"/>
</FlexBox>

Another way is a using a Toolbar and a ToolbarSpacer. But of course a Toolbar should only be used, when it makes sense to use a Toolbar.

<Toolbar>
    <Text text="Text1" textAlign="Begin"/>
    <ToolbarSpacer/>
    <Text text="Text2" textAlign="End"/>
</Toolbar>

[SAPUI5] Get data of an Item of a List or Table

All options have in common that you first try to get the binding context from the list/table element via the event. Having the right context, you can either use the getProperty() function to get a specific property, or use the getObject() function to get all data.

onClick: function (oEvent) {
    // Option 1
    oEvent.getParameters().item.getBindingContext().getProperty("ID") 
    // Option 2
    oEvent.getParameters().item.getBindingContext().getObject().ID
    // Option 3
    oEvent.getParameter("item").getBindingContext().getObject().ID 
    // Option 4
    oEvent.getSource().getBindingContext().getObject().ID 
}

Note: When using a List, it’s oEvent.getParameters().listItem instead of oEvent.getParameters().item.

Or you could also use the sPath property from the binding context and directly get the data from the model.

onClick: function (oEvent) {
    // Option 5
    const sPath = oEvent.getSource().getBindingContext().sPath 
    // 5a
    this.getView().getModel().getProperty(sPath).ID 
    // 5b
    this.getView().getModel().getProperty(sPath + "/ID") 
}

[SAPUI5] Get Icon for MimeType

API Reference IconPool: https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.core.IconPool

In my case I used a custom formatter and the getIconForMimeType() function from the IconPool to get the required Icons for my list items.

myView.xml

icon="{path: 'mimeType', formatter: '.formatter.getIconForMimeType'}">

formatter.js

        getIconForMimeType: function(sMimeType) {
           return sap.ui.core.IconPool.getIconForMimeType(sMimeType)
        }

[SAPUI5] Get i18n texts

To simply get access to i18n texts, I useally add this helper function to my BaseController.js

// helper for direct access to the ResourceBundle getText() function
getText : function (sTextKey, aParamter) {
    return this.getOwnerComponent().getModel("i18n").getResourceBundle().getText(sTextKey, aParamter)
}

Texts can then be read in every controller with

// i18n: objects=Amount of objects: {0}
this.getText("objects", [iLength])

[SAPUI5] Parse error message

If the error response is type json:

        oModel.callFunction("/myFunction", {
          method: "GET",
          urlParameters: {
            ID: myID,
          },
          success: oData => console.log(oData),
          error: oError => MessageBox.error(JSON.parse(oError.responseText).error.message.value, { title: "An error occurred" })
        });

If the error response is coming from a Gateway and has an XML body (link):

 MessageBox.error(jQuery.parseXML(oError.response.body).querySelector("message").textContent)

[SAPUI5] Call function of another controller using EventBus

https://sapui5.hana.ondemand.com/#/api/sap.ui.core.EventBus%23overview

In the receiving controller you need to subscribe your eventId and function you want to call from the second controller:

// Attaches an event handler to the event with the given identifier on the given event channel            
this.getOwnerComponent().getEventBus().subscribe("Default", "myEventId", () => {
    this._myFunctionIWantToCall();
});

The sending controller has to publish the event to trigger the function call:

// Fires an event using the specified settings and notifies all attached event handlers.
this.getOwnerComponent().getEventBus().publish("Default", "myEventId", {});

[SAPUI5] Get and set properties of a binded model and submit changes

Get:

const oModel = this.getView().getModel()
const sPath = this.getView().getBindingContext().sPath
const sID = oModel.getProperty(sPath+"/ID")

Set:

const newID = "12345"
oModel.setProperty(sPath+"/ID", newID)

When using the set property function, you can now submit your changes this way:

        // First check if there are any changes    
        if (!oModel.hasPendingChanges()) {
           MessageToast.show("Nothing to do!")
           return
        }
        
        // Now submit your changes
        oModel.submitChanges({
          success: () => MessageToast.show("Success!"),
          error: (err) => alert(err)
        })

This way is much more comfortable, than using oModel.update().

[SAPUI5] Filter on Model read

this.getModel().read("/Object", {
                filters: [
                    new Filter({
                        path: "firstName",
                        operator: FilterOperator.EQ,
                        value1: "Max"
                    }),
                    new Filter({
                        path: "lastName",
                        operator: FilterOperator.EQ,
                        value1: "Mustermann"
                    })
                ],
                success: oData => { },
                error: err => { }
});

[SAPUI5] Binding with filter on XML View

https://sapui5.hana.ondemand.com/sdk/#/topic/5338bd1f9afb45fb8b2af957c3530e8f.html

There are two ways to use a filter.

Option 1:

items="{
				path: '/myItems',
				parameters : {
				  $filter : 'itemName eq \'myItemName\'',
				  $orderby : 'createdAt desc'
				},
}">

Option 2:

items="{
				path: '/myItems',
				parameters : {
				  $orderby : 'createdAt desc'
				},
				filters : {                                     
				  path : 'itemName ',
				  operator : 'EQ',
				  value1 : 'myItemName'
				},
}">