Personal Insights
Random collection of useful code fragments for CAP Fiori Elements and SAPUI5
This blog post is dedicated to being a random collection of useful code fragments you might want to use. As any of these weren’t easy to find in documentation or code samples, my intention is to share some code fragments including a description, so whenever you google something, and you don’t see any answered question on SAP Community or StackOverflow, you land here 🙂
This may result in a series of random collections, but this one is mainly focussing on SAPUI5 and Fiori Elements for CAP. Potential backend code is written in NodeJS. Be aware that some solutions may not use best practices or could be potentially already replaced by a cleaner solution. However, the code fragments shall be still working. You may see other code fragments of other solutions included or used.
SAPUI5 masked IBAN field including validation
Although IBAN validation may sound simple, it is more complicated as you’d expect. You might know that IBANs don’t have a fixed length, they have country-depending lengths. Furthermore, they also can include characters.
Despite that the SAPUI5 MaskInput is only designed to receive a string of arbitrary length, it can be still used given the maximum size an IBAN can be.
The code fragment for the view looks as follows:
<MaskInput id="iBankAccountIBAN" change="validateIBAN" fieldGroupIds="RegForm" value="{path: 'BankAccountIBAN', type: 'sap.ui.model.type.String'}" mask="LLNN XXXX XXXX XXXX XXXX XXXX XXXX XXXX"
placeholderSymbol=" " placeholder="" required="true">
<rules>
<MaskInputRule maskFormatSymbol="L" regex="[A-Za-z]"/>
<MaskInputRule maskFormatSymbol="N" regex="[0-9]"/>
<MaskInputRule maskFormatSymbol="X" regex="[A-Za-z0-9]"/>
</rules>
</MaskInput>
The matching validation logic in the controller looks as follows:
validateIBAN: function (oEvent) {
var value = oEvent.getParameter("value");
this.markFieldError(oEvent.getSource(), !this._isValidIBANNumber(value) ? this.oBundle.getText("noValidIBAN") : "");
},
_isValidIBANNumber: function (sValue) {
var oIBANLanguageLengths = {
AD: 24, AE: 23, AT: 20, AZ: 28, BA: 20, BE: 16, BG: 22, BH: 22, BR: 29,
CH: 21, CR: 21, CY: 28, CZ: 24, DE: 22, DK: 18, DO: 28, EE: 20, ES: 24,
FI: 18, FO: 18, FR: 27, GB: 22, GI: 23, GL: 18, GR: 27, GT: 28, HR: 21,
HU: 28, IE: 22, IL: 23, IS: 26, IT: 27, JO: 30, KW: 30, KZ: 20, LB: 28,
LI: 21, LT: 20, LU: 20, LV: 21, MC: 27, MD: 24, ME: 22, MK: 19, MR: 27,
MT: 31, MU: 30, NL: 18, NO: 15, PK: 24, PL: 28, PS: 29, PT: 25, QA: 29,
RO: 24, RS: 22, SA: 24, SE: 24, SI: 19, SK: 24, SM: 27, TN: 24, TR: 26
};
var iban = String(sValue).toUpperCase().replace(/[^A-Z0-9]/g, ''), // keep only alphanumeric characters
code = iban.match(/^([A-Z]{2})(\d{2})([A-Z\d]+)$/), // match and capture (1) the country code, (2) the check digits, and (3) the rest
digits;
// check syntax and length
if (!code || iban.length !== oIBANLanguageLengths[code[1]]) {
return false;
}
// rearrange country code and check digits, and convert chars to ints
digits = (code[3] + code[1] + code[2]).replace(/[A-Z]/g, function (letter) {
return letter.charCodeAt(0) - 55;
});
// final check
return this._mod97(digits) === 1;
},
_mod97: function (sIBANFragment) {
var checksum = sIBANFragment.slice(0, 2), fragment;
for (var offset = 2; offset < sIBANFragment.length; offset += 7) {
fragment = String(checksum) + sIBANFragment.substring(offset, offset + 7);
checksum = parseInt(fragment, 10) % 97;
}
return checksum;
},
markFieldError: function (oControl, sError) {
if (oControl !== undefined) {
if (sError) {
oControl.setValueStateText(sError);
oControl.setValueState("Error");
} else {
oControl.setValueState("None");
}
}
},
Complex if/elseif/else constructs in CAP Service Annotation
Whenever you have a complex construct in a CAP service, you can always go back and use standard (HANA)SQL code to implement this logic. Be aware that CAP CDL still requires you to define the type of column you add.
entity BP as
select from my.BP {
*,
(
case
when
BPSalutation = '01'
then
'Herr ' || BPFirstName || ' ' || BPSurName
when
BPSalutation = '02'
then
'Frau ' || BPFirstName || ' ' || BPSurName
when
BPSalutation = '03'
then
'Firma ' || BPSurName
else
' '
end
) as BPFullName : String,
BPStreet || ' ' || BPHouseNumber as BPAddress : String,
BPZip || ' ' || BPCity as BPCityFull : String
};
Fiori Elements Facet Hiding
In Fiori Elements, you can use UI.Hidden to dynamically show or hide a facet based on a value. The following example shows you a service annotation, where the logic is implemented and the Fiori Elements CDS annotation.
entity Table @readonly as
select from my.Table {
*,
// unequals because boolean is about hiding or not
(
case
when
TableColumnOne != false and TableColumnCountry = 'LI'
then
true
else
false
end
) as CountrySpecific : Boolean,
}
Facets : [
...
{
$Type : 'UI.ReferenceFacet',
Label : 'Landesspezifische Information',
Target : '@UI.FieldGroup#CountryDetails',
![@UI.Hidden]: CountrySpecific
}
...
]
Fiori Elements String Concat
A string concat is pretty difficult in CAP CDS Fiori Elements annotations. As many help documents are referring to ABAP CDS or an XML Annotation, here is the following example done in CAP CDS Fiori Elements:
HeaderInfo : {
...
Description : {
Value : {
![$edmJson]: {
![$Function]: 'odata.concat',
![$Apply]: [
'Veranschlagte Summe: ',
{ ![$Path] : 'SalesProposition' },
' CHF'
]
}
}
}
},
I hope you enjoy this random collection of code. Maybe there will be soon part 2 🙂
Hi Leo,
Good blog! Found it useful. There is 1 issue that i am facing. If i have to concatenate 2 properties with in a table. How can i do it. When i use the below code it throws error.
Table LineItem
Thanks,
Kachin
What error occurs? Some issue with duplicate id?