Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
jorge_sousa
Active Participant
1,983
This short document explain one possible alternative to avoid the utilization of code in the "onInitialization", mainly when we need to improve performance in our SAC AD (when it's possible).

When we introduce code in the "onInitialization" we are stacked with the performance of execution sequencial instructions one by one. In some cases just to introduce code "onInitialization" we increase the duration in more 5 seconds.

In the below points I want to explain how we can use an alternative option to initialize our application without of the use of "onInitialization" in the canvas.

Alternative to "onInitialization"


To achieve this we need to use two techniques:

  1. Create a Custom Widget (CW).

  2. Use of onPostMessageReceive.


"onPostMessageReceive" is an event called when the application receives a message from another component like a hosting page or a custom widget. It's important to check the origin of this post messages.


In this alternative the idea is to create a simple CW with a simple property (Builder Panel) that allows to specify the "message" / "method" to send as a postMessage. The code can be inserted in "onCustomWidgetAfterUpdate(changedProperties)".

As son as the CW is loaded during the runtime of the application the "postMessage" is sent to the application and the event "onPostMessageReceived" is triggered. Here is where we can call the list of functions or instructions to execute.

Use of Simple Custom Widget (CW)


This simple CW must have at least:

  1. The JSON file definition.

  2. The Javascript for the main/core CW definition.

  3. The Javascript for the builder panel properties definition.


You can find more details how to create a CW in some blogs or also in the SAP Help:

https://help.sap.com/docs/SAP_ANALYTICS_CLOUD/0ac8c6754ff84605a4372468d002f2bf/2524b21ac5ec45649a64f...

The JSON file could be for example as the below one:
{
"name": "SAC OnInitialization",
"description": "SAC OnInitialization Avoid CW",
"eula": "EULA",
"vendor": "jmlds",
"license": "1.0",
"id": "com.sap.jmlds.oninitialization.widget",
"newInstancePrefix": "SACOnInitializationAvoidCW",
"version": "1.0.0",
"icon": "",
"webcomponents": [
{
"kind": "main",
"tag": "com-sap-jmlds-oninitialization-main",
"url": "https://myserver.com/tools/performance/sacperf_main.js?ver=1.0.2",
"integrity": "" ,
"ignoreIntegrity": true

},
{
"kind": "builder",
"tag": "com-sap-jmlds-oninitialization-bp",
"url": "https://myserver.com/tools/performance/sacperf_bp.js?ver=1.0.1",
"integrity": "",
"ignoreIntegrity": true
}
],
"properties": {
"width": {
"type": "integer",
"default": 50
},
"height": {
"type": "integer",
"default": 20
},
"method": {
"type": "string",
"description": "Method",
"default": "onInitialization"
}

},
"methods": {
"clear": {
"description": "Clear the resultset"
}
},
"events": {
"onClick": {
"description": "Only for Visible Process Click"
}
}
}

The builder panel JavaScript file must contains the property for the "method" / "message" configuration:
(function()  {
let base = document.createElement("template");
base.innerHTML = `
<form id="frmSacPerf">
<fieldset>
<legend>Method Call</legend>
<table>
<tr>
<td>Name of the Method</td>
<td><input id="id_method" type="text" size="20" maxlength="25"></td>
</tr>
</table>
<input type="submit" style="display:none;">
</fieldset>
</form>
<style>
:box {
display: block;
padding: 1px 1px 1px 1px;
}
</style>
`;

class PanelSacPerf extends HTMLElement {
constructor() {
super();
this._shadowRoot = this.attachShadow({mode: "open"});
this._shadowRoot.appendChild(base.content.cloneNode(true));
this._shadowRoot.getElementById("frmSacPerf").addEventListener("submit", this._submit.bind(this));
}

_submit(e) {
e.preventDefault();
this.dispatchEvent(new CustomEvent("propertiesChanged", {
detail: {
properties: {
method: this.method
}
}
}));
}

set method(setMethod) {
this._shadowRoot.getElementById("id_method").value = setMethod;
}

get method() {
return this._shadowRoot.getElementById("id_method").value;
}
}

customElements.define("com-sap-jmlds-oninitialization-bp", PanelSacPerf);
})();

The main JavaScript that must send the message to the canvas receiver must have at least, the definition of the template, the constructor, the declaration of the custom element and the function / event "onCustomWidgetAfterUpdate(changedProperties)":
(function () {
let template = document.createElement('template');
template.innerHTML =
`<button type="button" id="myBtn">SACOnInitializationAvoidCW</button>` ;

class SacPerf extends HTMLElement {
constructor() {
super();
this.init(this);
}

init(e) {
console.log("...Init");
let shadowRoot = this.attachShadow({mode: "open"});
shadowRoot.appendChild(template.content.cloneNode(true));
this.addEventListener("click", event => {
var event = new Event("onClick");
this.fireOnClick();
this.dispatchEvent(event);
});
}

onCustomWidgetBeforeUpdate(changedProperties)
{
}
onCustomWidgetAfterUpdate(changedProperties)
{
if ("method" in changedProperties) {
this.$method = changedProperties["method"];
window.postMessage(this.$method,"https://mytenant.eu10.hcs.cloud.sap");
}

}
connectedCallback()
{
var msg="connectedCallback";
//window.postMessage(msg,"https://mytenant.eu10.hcs.cloud.sap");
}
fireOnClick() {
console.log("OnClick Triggered");
}
}

customElements.define('com-sap-jmlds-oninitialization-main', SacPerf);
})();

Executing the instructions moved from onInitialization


When the CW is loaded and the event "onCustomWidgetAfterUpdate" is triggered with the postMessage we are triggering also in the Canvas the function "onPostMessageReceived" and here we can execute the instructions moved from the "onInitialization". The next sample is a piece of the application used as base for those tests and to document this sample:
switch(message){
case "onInitialization_1":
StartTime = Date.now();
console.log("#### Load App... ####");
Application.showBusyIndicator("Loading...");
SCRO_Utils.pauseRefresh(true);
SCRO_Utils.funcFillSalesMCombo();
break;
case "onInitialization2":

Having the code onInitialization


In this application sample, having all the instructions onInitialization the application takes more 5 seconds to show the result. The below are the instructions moved:
StartTime = Date.now();
console.log("#### Load App... ####");
Application.showBusyIndicator("Loading...");
SCRO_Utils.pauseRefresh(true);
SCRO_Utils.funcFillSalesMCombo();
console.log("#### Initialization 2 ####");
SCRO_Utils.funcFillLocateCombo();
SCRO_Utils.funcFillDateCombo();
console.log("#### Initialization 3 ####");
SCRO_Utils.pauseRefresh(false);
if(varFunctionsCompleted>=5){
Panel_1.setVisible(true);
Application.hideBusyIndicator();
Chart_6.getForecast().setType(ForecastType.Auto);
Chart_11.getForecast().setType(ForecastType.Auto);
EndTime = Date.now();
console.log("#### App Finished. Time Taken=" + (Math.floor((EndTime-StartTime)/1000)).toString());
}

Here is the simple application created as an example for this experience:



Potential uses of postMessage + CW


We can use the postMessage with a CW to improve our application, for example:

  • As a CW menu passing the values to variables, parameters, ... in our application without the need to refresh the window or the reload of the full application.

  • As a CW that calls custom functions created in our application without the need to pass in the URL variables.

  • As a CW that activate / trigger any standard widget. For example to link from CW to another widgets.

  • ...


 
2 Comments
Labels in this area